为锦标赛系统分配奖品
Posted
技术标签:
【中文标题】为锦标赛系统分配奖品【英文标题】:Distribute prizes for a tournament system 【发布时间】:2010-08-04 19:30:27 【问题描述】:我正在寻找一种在 x 个单位之间分配数字的方法。我什至不知道如何表达这个词,所以我举个例子:
有一个总奖金为 1000 美元的锦标赛。我希望前 20 名获胜者/参赛者能从中赢得一些东西。我需要一个数学算法/公式,将其分配给这些玩家,并赋予我控制分配的某些其他因素的能力。
例如,我希望排名第一的获胜者将获得 300 美元。排名第二的获胜者将获得较小的百分比。总分配必须给每个人一些东西,直到排名前 20 的获胜者(最后一个)将获得至少 X$。 X$ 是我想要控制的另一个因素。
有什么想法吗?这个问题有名字吗(那个名字是什么)?有代码示例吗?
编辑 #1 - 我的第一个提案:
#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();
这是我所能达到的。例如,如果将“WINNERS”设置为 5,则该算法不会达到“TOTAL”数量(本例中为 100)或更接近(我总共得到 83) .
克里斯蒂的解决方案:
#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();
【问题讨论】:
没有更多的约束,不可能定义一个算法!你想要什么样的分布?线性?二次方?还有什么? 实际上有无数种方法可以做到这一点,在这个阶段这并不是一个真正与编程相关的问题。 另外,除了上面提到的两个因素之外,我还想控制另一个我定义为“势头”的因素:奖品减少的步骤,从#1获胜者到# 20(最后)。 @Oli Charlesworth:相信我,我不知道怎么称呼它。我希望你能建议(:@torak:我确信有几种方法可以做到这一点,是的,我确实认为这是一个与编程相关的问题,否则我们也不会有“数学”标签。 @Poni:你现在有 4 个可能不兼容的约束(总、最大值、最小值和斜率)。 【参考方案1】:现在是凌晨 1:15,我正在解数学题 :))。 使用算术级数。 我全部使用定义,所以您可以轻松更改它们。
#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;
输出:
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
如您所见,它们的总和正好是 1000.00$ :D
其他结果: 输入:
#define last_prize 30
#define total_prizes 5
输出:
1) 370.00
2) 285.00
3) 200.00
4) 115.00
5) 30.00
TOTAL SUM:1000.00
【讨论】:
!!!!!! @#$#@ !!!!!!!!!你刚刚在我脸上露出了大大的笑容!!!这里也是01:15!你住在哪里?再次,非常感谢你,没有什么可以表达的!我要在剩下的晚上玩/学习你的代码(:!我知道你在en.wikipedia.org/wiki/Arithmetic_sequence实现了公式对吗? 是的,从那里有 2 个公式。我住在罗马尼亚:) 我想我要睡觉了。这段代码没问题,我喜欢制作算法:D。如果您不理解代码中的任何内容,请询问。晚安! 存在以下约束的问题:money=1000。最后一奖=100。总奖品=20。 #1 获胜者获得零。 #19 得到 94.74。 #20 得到 100。有什么办法解决吗?明天吧? (:祝你有个美好的夜晚! 代码不起作用,因为最后一个位置不能是 100 美元。 100$ 是最小的奖金,因此至少应支付 20*100$=2.000$:)。 注意到当值为:money=1000, last_prize=100, total_prizes=9 【参考方案2】:你可以做一个简单的公式。
#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;
这将输出:
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
但是您可以将值更改为您想要的任何值:)。 这只是一种快速简便的方法。
这个算法的最初想法是: 一等奖:所有奖金的 30% (1000$) = ~330$ 二等奖:其余的 30% (670 美元) = ~201 三等奖:其余的 30%……等等…… 如果您将 (15+(20-i)) 替换为 20,假设您会得到以下输出: 只需更改该值即可获得不同的结果。
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
编辑: 还有一件事情。在使用该算法分割所有资金后,可能还剩下一些钱(因为最后一个从其余的中获得 x%)。您可以将剩余的添加到第一位...
【讨论】:
非常感谢 Cristy,但它不适用于所有组合,也不能生成总和为 1000 的值(或接近,第二个输出的总和约为 980 和一点) )。 @Poni 正如我在编辑中所说,可能还有一些钱可以用来购买威士忌 :))(开个玩笑)。把剩下的钱加到第一位。这只是一个简单的算法,如果你想要更复杂的东西,你应该检查这个问题的一些数学解决方案(算术/几何级数或类似的东西) 查看我对 OP 的编辑。可能会为您提供更好的解决方案(:再次感谢,非常感谢您的努力! 同意您的编辑,但在此之前我会尝试解决它,以便更好地分发它。【参考方案3】:我遇到了池中的这个问题 - 我希望 3 个级别的个人奖项具有相同的相对比率(70%/20%/10%),但我认识到平局的可能性,所以我必须考虑到这一点。我不想只是平分底池然后颁发奖品,因为您最终可能会获得并列第二名,而个人第二名获得者的收入少于第三名。
P(i) = 奖品大小 N(i) = 获奖人数
1) 总和(超过 i)P(i)*N(i) = $1000
2) P(1)/P(2) = 70/20
3) P(2)/P(3) = 20/10
在我的例子中,3 个未知数中的 3 个方程 - 我求解得到一个唯一解。
对于您的示例,P(1) = 300 美元。我只想指定奖品的连续比率并求解线性方程组。
还可以考虑查看here,了解最近英国公开锦标赛的高尔夫奖品分配情况。我并不是说 PGA 可以比这个网站上的人才做得更好,但它证明了你提出的问题。
【讨论】:
其实它是一个问题的代数解,而不是算法,所以不容易编码。如果将问题表述为 n 个未知数中的 n 个方程,则可以使用一般线性代数求解器求解每个未知数。【参考方案4】:假设总资金为 M,您希望在 n 个池中分配,这样第一个人将获得比第二个人多 k 倍,第二个人比第三个人多 k 倍,依此类推。假设最后一个得到x金额,那么
x + k*x + k^2*x ... k^(n-1)*x = M x(k^n-1)/(k-1) = M
根据您选择和分配资金的 k 值从这个方程求解 x :-)
【讨论】:
【参考方案5】:Cristy 第一行的公式是错误的。 first_prize=2*money/total_prizes+last_prize; 应该是 first_prize=2*money/total_prizes - last_prize;
这是我在 python 中的解决方案,这将为***赢家增加剩余金额。
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
【讨论】:
【参考方案6】:我花了几个小时试图提出一种分配奖品的算法。这是基于我在各种论坛上看到的东西的解决方案。这段代码是用 Ruby 编写的。这对我很有效。
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
【讨论】:
以上是关于为锦标赛系统分配奖品的主要内容,如果未能解决你的问题,请参考以下文章