Distribute prizes for a tournament system - c++

I'm looking for a way to distribute a number across x units. I don't even know how to put this words so I'll give an example:
There's a tournament in which the total prize is $1000. I want that the top 20 winners/entrants will win something out of it.I need a mathematical algorithm/formula which will distibute it across those players, and which gives me the power to control certain other factors of the distribution.
A factor for example is that I want the top #1 winner will get $300. The top #2 winner will get smaller percentage of it. The total distribution must give everyone something, until the top #20 winner (the last one) which will get at least X$.
X$ is another factor I want to control.
Any idea? Does this problem has a name (and what's that name is)? Any code example?
Edit #1 - my first proposal:
#include <conio.h>
#include <vector>
#define TOTAL 100
#define WINNERS 15
#define FIRST_WINNER_PERCENTAGE 0.30
void distribute_1(::std::vector<double> * const prizes)
{
prizes->clear();
double total = TOTAL;
double winning_percentage = FIRST_WINNER_PERCENTAGE;
double slope = 0.5;
int winners = WINNERS;
double winning = 0;
for(int i = 0; i < winners; i++, total -= winning, winning_percentage /= 2)
{
winning = total * winning_percentage;
prizes->push_back(winning);
}
}
void distribute_2(::std::vector<double> * const prizes)
{
prizes->clear();
double total = TOTAL;
double winning_percentage = FIRST_WINNER_PERCENTAGE;
double slope = 0.5;
int winners = WINNERS;
double winning = 0;
for(int i = 0; i < winners; i++, total -= winning/*, winning_percentage /= 2*/)
{
winning = total * winning_percentage;
prizes->push_back(winning);
}
}
void distribute_3(::std::vector<double> * const prizes)
{
prizes->clear();
double total = TOTAL;
double winning_percentage = FIRST_WINNER_PERCENTAGE;
double slope = 0.0005;
int winners = WINNERS;
double winning = 0;
for(int i = 0; i < winners; i++, total -= winning, winning_percentage -= slope)
{
winning = total * winning_percentage;
prizes->push_back(winning);
}
}
void distribute_4(::std::vector<double> * const prizes)
{
prizes->clear();
double total = TOTAL;
double winning_percentage = FIRST_WINNER_PERCENTAGE;
double slope = 1 / WINNERS;
int winners = WINNERS;
double winning = 0;
for(int i = 0; i < winners; i++, total -= winning, winning_percentage -= slope)
{
winning = total * winning_percentage;
prizes->push_back(winning);
}
}
void main()
{
::std::vector<double> prizes;
distribute_1(&prizes);
distribute_2(&prizes);
distribute_3(&prizes);
distribute_4(&prizes);
double total_granted = 0;
for(int i = 0; i < WINNERS; i++)
{
total_granted += prizes[i];
printf("%lf\n", prizes[i]);
}
printf("-\n%lf\n", total_granted);
_getch();
}
This is as far as I could reach. The issue with this one is for example, if that if you set 'WINNERS' to 5 for example, the algorithm doesn't reach the 'TOTAL' amount (100 in this example) or even closer (I get a total of 83).
Cristy's solution:
#include <conio.h>
#include<iostream>
//using arithmetic progression
using namespace std;
int i;
float ratio;
float first_prize;
float s;
int main()
{
float money=1000;
const int total_prizes = 10;
float last_prize = 99;
float prizes[total_prizes+1];
/**/first_prize=2*money/total_prizes-last_prize; //last member of the progresion
ratio=(first_prize-last_prize)/(total_prizes-1);
prizes[total_prizes]=last_prize;
for(i=total_prizes-1;i>=1;i--){
prizes[i]=prizes[i+1]+ratio;
money-=prizes[i];
}
for(i=1;i<=total_prizes;i++){
printf("%d) %.2f\n",i,prizes[i]);
s+=prizes[i];
}
printf("TOTAL SUM:%.2f\n",s);
printf("Ratio: %.2f", ratio);
_getch();
}

It's 1:15 AM here and I'm solving maths :)).
Using arithmetic progression.
I made all using defines so you can easily change them.
#include<iostream>
//using arithmetic progression
using namespace std;
FILE *g=fopen("output.out","w");
#define last_prize 10
#define total_prizes 20
int i;
float prizes[total_prizes+1];
float money=1000;
float ratio;
float first_prize;
float s;
//a1=last_prize
//an=first_prize
int main(){
first_prize=2*money/total_prizes+last_prize; //last member of the progresion
ratio=(first_prize-last_prize)/(total_prizes-1);
prizes[total_prizes]=last_prize;
for(i=total_prizes-1;i>=1;i--)
prizes[i]=prizes[i+1]+ratio;
for(i=1;i<=total_prizes;i++){
fprintf(g,"%d) %.2f\n",i,prizes[i]);
s+=prizes[i];
}
fprintf(g,"TOTAL SUM:%.2f",s);
return 0;
}
OUTPUT:
1) 90.00
2) 85.79
3) 81.58
4) 77.37
5) 73.16
6) 68.95
7) 64.74
8) 60.53
9) 56.32
10) 52.11
11) 47.89
12) 43.68
13) 39.47
14) 35.26
15) 31.05
16) 26.84
17) 22.63
18) 18.42
19) 14.21
20) 10.00
TOTAL SUM:1000.00
As you can see they sum up to exactly 1000.00$ :D
Other results:
INPUT:
#define last_prize 30
#define total_prizes 5
OUTPUT:
1) 370.00
2) 285.00
3) 200.00
4) 115.00
5) 30.00
TOTAL SUM:1000.00

You could make a simple formula like.
#include<iostream>
using namespace std;
FILE *g=fopen("output.out","w");
int i;
int prizes[21];
int money=1000;
int main(){
for(i=1;i<=20;i++){
prizes[i]=(float)(15+(20-i))/100*money;
money-=prizes[i];
fprintf(g,"%d) %d\n",i,prizes[i]);
}
return 0;
}
This will output:
1) 340
2) 217
3) 141
4) 93
5) 62
6) 42
7) 29
8) 20
9) 14
10) 10
11) 7
12) 5
13) 4
14) 3
15) 2
16) 2
17) 1
18) 1
19) 1
20) 0
But you can change the values to anything you would like :).
This is just a fast&easy way to do this.
The starting ideea for this algorithm was:
1st prize: 30% from all the money (1000$) = ~330$
2nd prize: 30% from the rest (670$) = ~201
3rd prize: 30% from the rest... etc...
If you replace (15+(20-i)) with 20 let's say, you get this output:
Just change that value to get diffrent results.
1) 200
2) 160
3) 128
4) 102
5) 82
6) 65
7) 52
8) 42
9) 33
10) 27
11) 21
12) 17
13) 14
14) 11
15) 9
16) 7
17) 6
18) 4
19) 4
20) 3
EDIT:
And one more thing. After splitting all the money using that algorithms there may still be some money left (because the last one gets x% from the rest). You can add the left-over to the first place...

I had this problem for a pool - I wanted the 3 levels of individual prizes to have the same relative ratio (70%/20%/10%) but recognized the likelyhood of ties, so I had to account for that. I didn't want to just split the pot then award prizes since you might end up with ties for second and an individual second place winner getting less than the third place winner.
P(i) = Size of Prize
N(i) = Number of winners
1) Sum (over i) P(i)*N(i) = $1000
2) P(1)/P(2) = 70/20
3) P(2)/P(3) = 20/10
In my case, 3 equations in 3 unknowns - which I solved to get a unique solution.
For your example P(1) = $300. I would just specify successive ratios of prizes and solve the linear system of equations.
Also consider looking here for the distribution of golf prizes at the recent British Open Championship. I'm not saying that the PGA could do a better job than the talent at this website, but it a demonstration of your question in action.

Suppose total money M, you want distribute in n pools such that first person will get k times more than second and second gets k times more than third and so on. Suppose last one get x amount money then
x + k*x + k^2*x ... k^(n-1)*x = M
x(k^n-1)/(k-1) = M
Solve for x from this equation based on value of k you choose and distribute money :-)

Formula in first line of Cristy is wrong.
first_prize=2*money/total_prizes+last_prize;
It should be first_prize=2*money/total_prizes - last_prize;
Here is my solution in python, this will add residual amount to top winners.
starting_amount = (((winnings * 2) / float(no_of_winners)) - last_amount)
difference = (last_amount - starting_amount) / float(no_of_winners - 1)
for rank in range(1, no_of_winners + 1):
reward = starting_amount + difference * (rank - 1)
reward = round_amount(reward)
winnings -= reward
winning_amount[rank] = reward
residual_winnings = winnings
residual_shares = {1: 0.5, 2: 0.3, 3: 0.2}
if no_of_winners < 3:
winning_amount[1] += residual_winnings
else:
for rank in residual_shares:
reward = residual_winnings * residual_shares[rank]
reward = round_amount(reward)
winning_amount[rank] += reward

I spent a few hours trying to come up with an algorithm that will distribute prizes. Here is my solution based off things I saw on various forums. This code is in Ruby. This has worked great for me.
def self.get_prize_array(money,total_prizes)
prizes = []
p = 0.7 # tweek this for distribution of payout
n = total_prizes
l = money
(1..total_prizes).each do |r|
prizes[r-1] = ((1 - p) / (1 - p**n) * p**(r - 1)) * l # p**n is p to the nth power
end
return prizes
end

Related

Dynamic programming state calculations

Question:
Fox Ciel is writing an AI for the game Starcraft and she needs your help.
In Starcraft, one of the available units is a mutalisk. Mutalisks are very useful for harassing Terran bases. Fox Ciel has one mutalisk. The enemy base contains one or more Space Construction Vehicles (SCVs). Each SCV has some amount of hit points.
When the mutalisk attacks, it can target up to three different SCVs.
The first targeted SCV will lose 9 hit points.
The second targeted SCV (if any) will lose 3 hit points.
The third targeted SCV (if any) will lose 1 hit point.
If the hit points of a SCV drop to 0 or lower, the SCV is destroyed. Note that you may not target the same SCV twice in the same attack.
You are given a int[] HP containing the current hit points of your enemy's SCVs. Return the smallest number of attacks in which you can destroy all these SCVs.
Constraints-
- x will contain between 1 and 3 elements, inclusive.
- Each element in x will be between 1 and 60, inclusive.
And the solution is:
int minimalAttacks(vector<int> x)
{
int dist[61][61][61];
memset(dist, -1, sizeof(dist));
dist[0][0][0] = 0;
for (int total = 1; total <= 180; total++) {
for (int i = 0; i <= 60 && i <= total; i++) {
for (int j = max(0, total - i - 60); j <= 60 && i + j <= total; j++) {
// j >= max(0, total - i - 60) ensures that k <= 60
int k = total - (i + j);
int & res = dist[i][j][k];
res = 1000000;
// one way to avoid doing repetitive work in enumerating
// all options is to use c++'s next_permutation,
// we first createa vector:
vector<int> curr = {i,j,k};
sort(curr.begin(), curr.end()); //needs to be sorted
// which will be permuted
do {
int ni = max(0, curr[0] - 9);
int nj = max(0, curr[1] - 3);
int nk = max(0, curr[2] - 1);
res = std::min(res, 1 + dist[ni][nj][nk] );
} while (next_permutation(curr.begin(), curr.end()) );
}
}
}
// get the case's respective hitpoints:
while (x.size() < 3) {
x.push_back(0); // add zeros for missing SCVs
}
int a = x[0], b = x[1], c = x[2];
return dist[a][b][c];
}
As far as i understand, this solution calculates all possible state's best outcome first then simply match the queried position and displays the result. But I dont understand the way this code is written. I can see that nowhere dist[i][j][k] value is edited. By default its -1. So how come when i query any dist[i][j][k] I get a different value?.
Can someone explain me the code please?
Thank you!

Why is my character spawning at a 45 degree angle when I've coded it to be set to 0 degrees?

The title describes my problem, as you can see here my character is spawning at a 45 degree angle. The character always spawns at (0, 0)
I have created some code for animations that uses the character's position and desired position to calculate at what angle the character should be at. This angle is determined by using the percentage of distance the character has travelled to its destination (these destinations are only Y values. X is increased by 1 every tick). I have made an equation to determine the angle based on the percentage travelled. The equation: -(9/500)X^2 + (9/5)X. This is a parabola that intersects point (0, 0), (50, 45) ← 45 degree angle and (100, 0).
The code I made to use this equation is as follows:
float GetRotationDegrees(int Current, int Target, int LaneWidth) {
int numerator = Current - LaneWidth;
int denominator = Target - LaneWidth;
float X;
if (denominator == 0) X = 0;
else X = abs(numerator / denominator * 100);
return -(9/500)*pow(X,2)+(9/5)*X; // function: -(9/500)X^2 + (9/5)X.
}
The LaneWidth is always 400, Current is the character's current Y coordinate and Target is the target Y coordinate. At Y = 0 the equation should be -400 / -400 * 100 = 100. And when you put 100 in the equation you get 0, this value of 0 is then used like this:
SetActorLocation(FVector(1, sin(angle * PI / 180), 0).Rotation());
I am really confused right now because whenever I manually try this it won't work.
It is probably something stupid I did, I tend to look over things a lot of the time and am not that good at maths (I am also new to C++, so the mistake might be there too). If someone could help me I would really appreciate it!
(By the way, I know that the way that GetRotationDegrees decides X the angle will only return positive angles, I want to get this to work first)
Fixed it with this:
float GetRotationDegrees(int Current, int Target, int LaneWidth) {
if (Current == Target) return 0;
int MovingFrom;
if (Target != 0) MovingFrom = 0;
else if (Target > Current) MovingFrom = -LaneWidth;
else MovingFrom = LaneWidth;
float Percentage = float(Current - MovingFrom) / float(Target - MovingFrom) * 100;
if (Target < Current) Percentage = -Percentage;
bool isNegative = Percentage < 0;
if (isNegative) return -(-9 * pow(abs(Percentage), 2) / 500 + 9 * abs(Percentage) / 5);
return -9 * pow(Percentage, 2) / 500 + 9 * Percentage / 5;
}

Implementing Exponential Moving Average in C++

I am developing a small trading robot as an exercise. He receives stock prices day after day (represented as iterations).
Here's what my Trade class looks like:
class Trade
{
private:
int capital_;
int days_; // Total number of days of available stock prices
int daysInTrading_; // Increments as days go by.
std::list<int> stockPrices_; // Contains stock prices day after day.
int currentStock_; // Current stock we are dealing with.
int lastStock_; // Last stock dealt with
int trend_; // Either {-1; 0; 1} depending on the trend.
int numOfStocks_; // Number of stocks in our possession
int EMA_; // Exponential Moving Average
int lastEMA_; // Last EMA
public:
// functions
};
As you can see from my last two attributes, I wish to implement an Exponential Moving Average as part of a Trend Following Algorithm.
But I think I didn't quite understand how to implement it; here's my calcEMA function that simply calculates the EMA:
int Trade::calcEMA()
{
return ((this->currentStock_ - this->lastEMA_
* (2/(this->daysInTrading_ + 1)))
+ this->lastEMA_);
}
But when my stock values (passed in a file) are like such:
1000, 1100, 1200, 1300, 1400, 1500, 1400, 1300, 1200, 1100, 1000
As to make sure my EMA makes sense, and well... it does not !
Where did I go wrong on the operation?
Aditionally, what value should I give lastEMA if it's the first time I call calcEMA?
I believe that you are missing a parentheses in the "calcEMA" function. How about breaking the expression up into smaller expressions with temporary variables to hold intermediate results like this?
int Trade::calcEMA()
{
auto mult = 2/(timePeriod_ + 1);
auto rslt = (currentStock_ - lastEMA_) * mult + lastEMA_;
return rslt;
}
Also, as user PaulMcKenzie pointed out in the comment on your question, you are using the integer to do floating point calculation. You may consider using float or double to avoid possible truncation.
Here are my suggestions:
  An EMA like yours is defined for a time period. While daysInTrading is less or equal to timePeriod, lastEMA should be set to a normal average.
  Once daysInTrading is greater than your timePeriod you can start calling your "calcEMA" function with initialized lastEMA.
  Please, remember to update lastEMA after each call to the "calcEMA" function.
Here is my code for you:
#include <vector>
#include <list>
#include <iostream>
// calculate a moving average
double calcMA (double previousAverage,
unsigned int previousNumDays,
double newStock) {
auto rslt = previousNumDays * previousAverage + newStock;
return rslt / (previousNumDays + 1.0);
}
// calculate an exponential moving average
double calcEMA (double previousAverage,
int timePeriod,
double newStock) {
auto mult = 2.0 / (timePeriod + 1.0);
auto rslt = (newStock - previousAverage) * mult + previousAverage;
return rslt;
}
class Trade {
unsigned int timePeriod_ = 5;
double lastMA_ = 0.0;
std::list<double> stockPrices_;
public:
void addStock (double newStock) {
stockPrices_.push_back(newStock);
auto num_days = stockPrices_.size();
if (num_days <= timePeriod_)
lastMA_ = calcMA(lastMA_, num_days - 1, newStock);
else
lastMA_ = calcEMA(lastMA_, num_days - 1, newStock);
}
double getAverage() const { return lastMA_; }
};
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
int main() {
std::vector<double> stocks =
{1000, 1100, 1200, 1300, 1400, 1500,
1400, 1300, 1200, 1100, 1000};
Trade trade;
for (auto stock : stocks)
trade.addStock(stock);
std::cout << "Average: " << trade.getAverage() << std::endl;
return 0;
}
The operation is wrong, as you noticed.
Disclaimer I got this algorithm from wikipedia, and as such might no be accurate. Here (page 3) might be a better one, but I can't judge, I never used those algorithms and so have no idea what I'm talking about :)
c(EMA) = y(EMA) + a * (c(price) - y(EMA))
c(EMA) is current EMA
y(EMA) is previous EMA
a is some "random" value between 0 and 1
c(price) is current price
But you did almost the same thing:
c(EMA) = (c(price) - y(EMA) * b) + y(EMA)
I don't know why you did 2 / daysInTrading_ + 1, but this will not always be a value between 0 and 1 (actually, it might even be most of the time 0, because those are all intergers).
You put a parenthesis at the wrong place (after b, and not after y(EMA)).
So the operation will now look like this:
lastEMA_ + 0.5 * (currentStock_ - lastEMA_)
For the first lastEMA_, according to Wikipedia:
S1 is undefined. S1 may be initialized in a number of different ways, most commonly by setting S11 [First element in the list], though other techniques exist, such as setting S1 to an average of the first 4 or 5 observations.
The importance of the S1 initialisations effect on the resultant moving average depends on α; smaller α values make the choice of S1 relatively more important than larger α values, since a higher α discounts older observations faster.
There are generally two accepted forms of EMA.
The traditional:
m = 2/(1+n) // where n >= 1
EMA = m * currentPrice + (1-m) * previousEMA
rf the Wilder:
m = 1/n // where n >= 1
EMA Wilder = m * currentPrice + (1-m) * previousEMA

How to do logarithmic binning on a histogram?

I'm looking for a technique to logarithmically bin some data sets. We've got data with values ranging from _min to _max (floats >= 0) and the user needs to be able to specify a varying number of bins _num_bins (some int n).
I've implemented a solution taken from this question and some help on scaling here but my solution stops working when my data values lie below 1.0.
class Histogram {
double _min, _max;
int _num_bins;
......
};
double Histogram::logarithmicValueOfBin(double in) const {
if (in == 0.0)
return _min;
double b = std::log(_max / _min) / (_max - _min);
double a = _max / std::exp(b * _max);
double in_unscaled = in * (_max - _min) / _num_bins + _min;
return a * std::exp(b * in_unscaled) ;
}
When the data values are all greater than 1 I get nicely sized bins and can plot properly. When the values are less than 1 the bins come out more or less the same size and we get way too many of them.
I found a solution by reimplementing an opensource version of Matlab's logspace function.
Given a range and a number of bins you need to create an evenly spaced numerical sequence
module.exports = function linspace(a,b,n) {
var every = (b-a)/(n-1),
ranged = integers(a,b,every);
return ranged.length == n ? ranged : ranged.concat(b);
}
After that you need to loop through each value and with your base (e, 2 or 10 most likely) store the power and you get your bin ranges.
module.exports.logspace = function logspace(a,b,n) {
return linspace(a,b,n).map(function(x) { return Math.pow(10,x); });
}
I rewrote this in C++ and it's able to support ranges > 0.
You can do something like the following
// Create isolethargic binning
int T_MIN = 0; //The lower limit i.e. 1.e0
int T_MAX = 8; //The uper limit i.e. 1.e8
int ndec = T_MAX - T_MIN; //Number of decades
int N_BPDEC = 1000; //Number of bins per decade
int nbins = (int) ndec*N_BPDEC; //Total number of bins
double step = (double) ndec / nbins;//The increment
double tbins[nbins+1]; //The array to store the bins
for(int i=0; i <= nbins; ++i)
tbins[i] = (float) pow(10., step * (double) i + T_MIN);

Circumference of Sierpinski triangle

I'm currently doing the this problem for own practice. I manage to pass all the testcases, so I can't figure out whats wrong. My code is:
#include <iomanip>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;
int main(){
int num = 1;
while(true){
string line,stringRes;
getline(cin,line);
if(cin.eof()){break;}
long double shrinks = atof(line.c_str());
long double triangels = pow(3,shrinks);
long double length = 3/pow(2,shrinks);
long double res = floor(triangels* length * 3);
int i = 0;
while(res >= 10){
i++;
res = res/10;
};
if(shrinks == 1){
printf("Case %d: %d\n",num ,1);
}else{
printf("Case %d: %d\n",num ,i+1);
}
num++;
}
return 0;
}
for exampel when I input 1000 I get 178 and 10000 I get 1762.
Input Sample
0
1
5
10
100
Output Samle
Case 1: 1
Case 2: 1
Case 3: 2
Case 4: 3
Case 5: 19
For each case, display the case number followed by the number of decimal digits required to represent the integer portion of the circumference for the given number of iterations. Follow the format of the sample output.
The reason you get the wrong result is, as described earlier: you get overflow by using pow, but also because you - as you seem to have realized - used 3 as your start side length.
Here is an alternative, and correct, solution that is a bit shorter (without overflow):
The circumference (or perimeter) P(n) of a Sierpinski triangle of order n >= 0 can be shown to be:
P(n) = 3^(n + 1) / 2^n
I don't provide a proof since it's not necessary to solve the problem. However, it's rather easy to understand that this must be the case. One way is by calculating the perimeter of the first few orders of the Sierpinski triangle: 3, 9/2, 27/4, 81/8, ..., another is to think about how the circumference changes when you (1) "shrink" the shape by a factor of ½ and (2) "extend" the triangle by a factor of 3.
The number of digits D(x) in any natural number (of base 10) x is:
D(x) = 1 + floor(log10(x))
So to calculate the number of decimal digits in the Sierpinski perimeter of order n we calculate the number of digits in the integer part of P(n) = 3^(n + 1) / 2^n, i.e. D(floor(P(n))), which is also the solution to the problem:
D(floor(P(n))) = 1 + floor(log10(3^(n + 1) / 2^n)) = /log(a/b) = log(a) - log(b)/ =
= 1 + floor(log10(3^(n + 1)) - log10(2^n)) = /log10(a^b) = b * log10(a)/ =
= 1 + floor((n + 1) * log10(3) - n * log10(2))
C++ implementation that solves the problem:
/** Calculates the number of digits in the integer part of the perimeter of the Sierpinski triangle of order n */
/** Author: Fredrik Präntare, Date: 19/3/2016 */
#include <iostream>
#include <algorithm> // log10, floor
using namespace std;
int main(){
int c = 1, n;
while(scanf("%d", &n) != EOF){
int D_p = 1 + floor((n + 1) * log10(3) - n * log10(2));
printf("Case %d: %d\n", c, D_p);
c++;
}
}
You are overflowing the value of triangels. When you have
long double triangels = pow(3,shrinks);
Where shrinks = 10000 gives: 1.6313501853426258743032567291812e+4771.
The range of a long double where sizeof(long double) == 8 is 1.7E +/- 308.
More than likely you will need to use modular exponentiation to solve this problem.