为锦标赛系统分配奖品

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 

【讨论】:

以上是关于为锦标赛系统分配奖品的主要内容,如果未能解决你的问题,请参考以下文章

奖品分配-头条2019笔试题

数独 (dfs)

HDU 1426 Sudoku KillerDFS 数独

Buddy(伙伴)系统分配器之分配page

Buddy(伙伴)系统分配器之分配page

操作系统内存分配