Divide x into y parts by decreasing amount

后端 未结 3 2051

If I had $1000(variable) and I want to split that amount up and give it to 20(variable) people, but rather than give it evenly to each person, I want to give more to the 1st per

相关标签:
3条回答
  • 2021-01-25 22:23

    Formula is correct, needed a little touch.

    1. Don't cast float into int, data loss!
    2. When going within the for go from the first person to the n-1

      int people = 20;
      float prize = 1000;
      
      float k = (2 * prize) / ((people) * (people - 1));
      float sum = 0;
      
      for (int i = 1; i < people; ++i)
      {
          var personsPrize = i * k;
          sum += personsPrize;
          Console.WriteLine(personsPrize);
      }
      Console.WriteLine("sum = " + sum);
      
    0 讨论(0)
  • 2021-01-25 22:28

    Adding answer to Ensure prize pool doesn't award tied participants less than participants who scored worse

    Two things

    1. Incorrect, when assigning prices start from first person to the n-1 one person does't get prize, correct is start from first person to the n

    2. Valid basePrize noted with K is

      k = (2 * prize) / ((people) * (people + 1))

    Now the answer the other question:

    int totalPeople = 20;
    float prize = 5000;
    
    List<int> peopleScores = new List<int>();
    Random r = new Random();
    for (int i = 0; i < totalPeople; ++i)
    {
        peopleScores.Add(r.Next(0, 100));
    }
    
    var totalPeopleWithScore = peopleScores.Where(x => x > 0).Count();
    
    var groupedScores = peopleScores
        .Where(x => x > 0)
        .ToList()
        .GroupBy(x => x)
        .Select(grp => new
        {
            score = grp.Key,
            peopleScores = grp.ToList()
        })
        .OrderBy(g => g.score)
        .ToList();
    
    var groupCount = groupedScores.Select(x => new { count = x.peopleScores.Count() }).Select(z => z.count).Count();
    
    float basePrizeRate = 2 * prize / totalPeopleWithScore / (totalPeopleWithScore + 1);
    Console.WriteLine("Base Price rate: " + basePrizeRate);
    float sum = 0;
    var leaderboardPosition = 0;
    var totalWinners = 0;
    foreach (var positionScore in groupedScores)
    {
        var countWinner = positionScore.peopleScores.Count();
        Console.WriteLine();
        Console.WriteLine($"On leaderboard position : {groupedScores.Count() - leaderboardPosition} are {countWinner} winners with score: {positionScore.score}");
    
        float positionPrizePool = 0;
        for (int i = 1; i <= positionScore.peopleScores.Count(); ++i)
        {
            totalWinners++;
            positionPrizePool += totalWinners * basePrizeRate;
        }
        Console.WriteLine("Prize Pool " + positionPrizePool);
        var personPoolPrize = positionPrizePool / positionScore.peopleScores.Count();
        foreach (var x in positionScore.peopleScores)
        {
            Console.WriteLine($"Winner {totalWinners} won: {personPoolPrize}");
            sum += personPoolPrize;
        }
        leaderboardPosition++;
    }
    Console.WriteLine();
    
    Console.WriteLine("Total Prize: " + sum);
    Console.WriteLine("Total Winners: " + totalPeopleWithScore);
    
    0 讨论(0)
  • 2021-01-25 22:35

    You owe me a beer, actually a chug of beer!!

    Using Gauss distribution (N*(N+1))/2 you cannot have a slight margin over the competitors ranks, prizes have linear increase https://mathbitsnotebook.com/Algebra2/Sequences/SSGauss.html.

    What you need is something that increases exponentially or with a fixed ration, I want to solve your problem with a mathematical approach, so I will use a geometric progression https://mathbitsnotebook.com/Algebra2/Sequences/SSGeometric.html

    I won't add any other answer after this one, you have to build your own prize pool system!!

    For Geometric Distribution formula is:

    rankPrize = ((1 - distributionFactor) / (1 - distributionFactor ^ winners) * distributionFactor ^ (rank - 1)) * prize

    where distributionFactor - is between 0 and 1

    Play around with distribution Factor and chose the correct value for your system, I've chosen 0.8 because the gap between prizes is not that big!

    Here we go, fiddle link: https://dotnetfiddle.net/qmJnYd to play around and implementation:

    static void GaussDistributionPricePool()
            {
                Console.WriteLine("________________________________________________________");
                Console.WriteLine("Begin Gauss distribution price pool");
    
                int totalPeople = 20;
                float prize = 5000;
    
                List<int> peopleScores = new List<int>();
                Random r = new Random();
                for (int i = 0; i < totalPeople; ++i)
                {
                    peopleScores.Add(r.Next(0, 100));
                }
    
                var totalPeopleWithScore = peopleScores.Where(x => x > 0).Count();
    
                var groupedScores = peopleScores
                    .Where(x => x > 0)
                    .ToList()
                    .GroupBy(x => x)
                    .Select(grp => new
                    {
                        score = grp.Key,
                        peopleScores = grp.ToList()
                    })
                    .OrderBy(g => g.score)
                    .ToList();
    
                var groupCount = groupedScores.Select(x => new { count = x.peopleScores.Count() }).Select(z => z.count).Count();
                // Gauss formula. (N*(N+1))/2
                // https://mathbitsnotebook.com/Algebra2/Sequences/SSGauss.html
                float basePrizeRate = 2 * prize / totalPeopleWithScore / (totalPeopleWithScore + 1);
                Console.WriteLine("Base Price rate: " + basePrizeRate);
                float sum = 0;
                var leaderboardRank = 0;
                var totalWinners = 0;
                foreach (var positionScore in groupedScores)
                {
                    var countWinner = positionScore.peopleScores.Count();
                    Console.WriteLine();
                    Console.WriteLine("On leaderboard rank : " + (groupedScores.Count() - leaderboardRank) + " are " + countWinner + " winners with score: " + positionScore.score);
    
                    float positionPrizePool = 0;
                    for (int i = 1; i <= positionScore.peopleScores.Count(); ++i)
                    {
                        totalWinners++;
                        positionPrizePool += totalWinners * basePrizeRate;
                    }
                    Console.WriteLine("Prize Pool " + positionPrizePool);
                    var personPoolPrize = positionPrizePool / positionScore.peopleScores.Count();
                    foreach (var x in positionScore.peopleScores)
                    {
                        Console.WriteLine("Winner " + totalWinners + " won: " + personPoolPrize);
                        sum += personPoolPrize;
                    }
                    leaderboardRank++;
                }
                Console.WriteLine();
    
                Console.WriteLine("Total Prize: " + sum);
                Console.WriteLine("Total Winners: " + totalPeopleWithScore);
    
                Console.WriteLine("End Gauss distribution price pool");
                Console.WriteLine("________________________________________________________");
            }
    
    0 讨论(0)
提交回复
热议问题