Убедитесь, что призовой фонд не присуждает участникам с равным количеством очков меньше, чем участникам, набравшим худшие баллы

Если бы у меня было 1000 долларов (переменная), и я хочу разделить эту сумму и раздать ее 20 (переменным) людям, но вместо того, чтобы давать поровну каждому человеку, я хочу дать больше 1-му человеку и 2-му человеку, и т.п.

Таким образом, 20-й человек получает меньше всего, а 5-й человек получает 5-е место больше всего.

Люди сортируются в списке по количеству очков. Как я могу проверить, что люди с одинаковым количеством очков получают одинаковую сумму приза, при этом общая сумма приза распределяется между всеми людьми?

Формула на данный момент:

int people = 20;
float prize = 1000;

List<int> list = new List<int>();

for( int i = 0; i < people; ++i )
{
    list.add(Random.Range(0,100));
}

list.Sort();

float k = (2 * prize) / ((people) * (people - 1));
float sum = 0;

for (int i = 1; i < list.Count-1; ++i)
{
    var personsPrize = i * k;
    sum += personsPrize;
    Console.WriteLine(personsPrize);
}
Console.WriteLine("sum = " + sum);

Первое место получит 25% от общего призового фонда. Второе место получает 20%, а третье место получает 15%, затем остальное делится между оставшимися людьми, при этом люди с одинаковым баллом получают одинаковую сумму.

Что должно произойти, чтобы люди, получившие равные первые равные? Они не должны получать меньше, чем кто-либо другой, но и не должны удваивать сумму первого приза.

я думаю, что алгоритм будет зависеть от того, насколько сильно должен варьироваться приз, т.е. получает ли первое место дважды второе место или значение 2-го места + 10 или 10% больше

yawnobleix 28.05.2019 11:55

Первое место получит 25% от общего призового фонда. Второе место получает 20%, а третье место получает 15%, затем остальное делится между оставшимися людьми, при этом люди с одинаковым баллом получают одинаковую сумму.

Cypras 28.05.2019 12:03

а что делать, если есть два усталых для первого? они делят 25% или каждый получает по 25%?

yawnobleix 28.05.2019 12:14

Вы ожидаете, что они разделят между собой суммы 1-го и 2-го места ((25% + 20%)/2), что оставит 3-е и последующие места без изменений. Кипрас, однако, устанавливает здесь правила.

Steve Todd 28.05.2019 12:17

Я не знаю, как лучше всего поступить с этим, потому что если 4 приравняют первое место, это будет весь призовой фонд. Но если мы разделим его, у них может оказаться меньше пользователей, чем более низкие.

Cypras 28.05.2019 12:18

В спецификации все еще есть дыры. А если меньше 6 человек? 4-й получит больше, чем 1-й, если их всего 4, и больше, чем 2-й, если их 5.

Steve Todd 28.05.2019 12:46

Будет минимум 20 человек

Cypras 28.05.2019 12:50

Это не дубликат, потому что первый вопрос был об ошибке цикла, а этот касается обеспечения того, чтобы возникновение ничьих не нарушало то, что каждый участник с более низким результатом должен получить меньший приз, чем любой один участник с более высоким результатом.

Ruzihm 28.05.2019 20:25

@Cypras помнишь меня из исходного вопроса? У меня есть ответ на этот вопрос, я не шучу, но я не могу его предоставить, потому что он помечен как дубликат. Порекомендуйте изменить заголовок вопроса на что-то «Распределение призового фонда в процессе», чтобы его можно было открыть повторно, потому что люди (не ботинки) ищут по заголовку при переполнении стека любые совпадения, но они не читают вопрос!

SilentTremor 28.05.2019 20:48

@SilentTremor Хорошая идея, я пошел дальше и изменил название

Ruzihm 28.05.2019 20:54

Как я могу пометить его как не дублирующийся?

Cypras 28.05.2019 21:10

Я поставлю другой ответ на оригинал.

SilentTremor 28.05.2019 21:36

Вы можете закрыть этот

SilentTremor 28.05.2019 21:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
13
160
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это может быть решением:

class People
{
    public int ID { get; set; }
    public int Rank { get; set; }
    public float? Prize { get; set; }
}

//Оставляем за первым, вторым и третьим лицом 60% приза. // Представьте себе, например, что 5 человек имеют самый высокий ранг 20. в этом случае сумма первого места составляет 125%. Это невозможно.

Для меня у вас должен быть другой параметр, чтобы выбирать первые места.

Или вы должны изменить свою логику ранжирования: например, если сумма процентов превышает 100% или 90% (или процент, который вы определите), уменьшите процент первого места, второго и третьего мест и т. д.

Представьте, что у вас 4 первых места, 1 второе и 1 третье место.

В этом случае у вас есть (4 * 25%) + 20% + 15% = 135%. Это означает, что вы должны уменьшить свои 25%, например, до 15%, второе место до 10% и третье место до 5%.

в этом случае у вас будет (4 * 15%) + 10% + 5% = 75 процентов за ваши самые высокие места и вы будете раздавать 25% другим пользователям.

    private void CheckPrices()
    {
        float prize = 1000;
        Random rnd = new Random(1);
        var peopleList = new List<People>();
        for (int i = 0; i < 20; i++)
        {
            peopleList.Add(new Test.People() { ID = i + 1, Rank = rnd.Next(5, 100) });
        }


        var firstPrize = prize * 25 / 100;
        var secondPrize = prize * 20 / 100;
        var thirstPrize = prize * 15 / 100;

        int i = 0;
        //Sets first places prizes.
        foreach (var person in peopleList.OrderByDescending(ro => ro.Rank))
        {
            i++;
            if (i == 1)
                person.Prize = firstPrize;
            else if (i == 2)
                person.Prize = secondPrize;
            else if (i == 3)
                person.Prize = thirstPrize;
            else
                break;
        }


        var totalRank = peopleList.Sum(ro => ro.Rank);
        float prizePerRank = (prize - (firstPrize + secondPrize + thirstPrize)) / totalRank;

        foreach (var person in peopleList.Where( ro=> ro.Prize == null))
        {
            person.Prize = person.Rank * prizePerRank;
        }

        //
        var totalPrizeDistributed = peopleList.Sum(ro => ro.Prize); //= 1000
    }
}

Мы еще не знаем, как OP хочет организовать призовую иерархию. Как вы можете предложить решение, если проблема не определена должным образом?

Steve Todd 28.05.2019 12:00

Проблема для меня ясна, он хочет распределить призы в зависимости от ранга пользователя. Чем больше у пользователя очков, тем больше пользователь зарабатывает. Я не понимаю, почему мы не можем понять проблему.

Coskun Ozogul 28.05.2019 12:04

Даст ли это пользователям с одинаковым количеством очков один и тот же приз, сохранив при этом общий призовой фонд? Похоже, так и будет.

Cypras 28.05.2019 12:08

Да. Но я должен изменить свой код, чтобы сохранить проценты для первых 3 мест.

Coskun Ozogul 28.05.2019 12:08

Есть ли способ отделить 3 лучших ранга и дать им 25, 20, 15 процентов от общего призового фонда, а затем передать оставшийся призовой фонд остальным людям?

Cypras 28.05.2019 12:10

Стив Тодд, голосование только за понижение бесполезно.

Coskun Ozogul 28.05.2019 12:10

Да, я модифицирую свой код, я собираюсь опубликовать модификацию.

Coskun Ozogul 28.05.2019 12:11

Как код будет обрабатывать несколько победителей, занявших первое место, если они набрали одинаковые баллы?

Cypras 28.05.2019 12:12

Это действительно умный способ обработки первых, вторых и третьих мест, как вы думаете, вы могли бы показать это в своем коде, как бы вы справились с этим? Многому учимся у вас!

Cypras 28.05.2019 12:32

Я собираюсь попытаться изменить свой код.

Coskun Ozogul 28.05.2019 13:37
Ответ принят как подходящий

Я бы сделал это, сначала разделив призовые фракции и определив, какие призы должны быть объединены из-за ничьей. Затем суммируйте объединенные дроби и разделите эту объединенную сумму поровну на всех связанных участников.

Это гарантирует, что сумма, полученная для каждого равного участника, будет меньше или равна наибольшей сумме приза, объединенной в одну, и больше или равна наименьшей сумме объединенного приза.

   public class Person
   {
      public Person(string name, int position)
      {
         Name = name;
         Position = position;
      }
      public string Name { get; set; }
      public int Position { get; set; }
   }

      static void Main(string[] args)
      {
         var winners = new Person[]
         {
            new Person("Test 1", 1),
            new Person("Test 2", 1),
            new Person("Test 3", 1),
            new Person("Test 4", 1),
            new Person("Test 5", 5),
            new Person("Test 6", 6),
            new Person("Test 7", 7),
            new Person("Test 8", 8),
            new Person("Test 9", 9),
            new Person("Test 10", 9),
            new Person("Test 11", 11),
            new Person("Test 12", 11),
            new Person("Test 13", 13),
            new Person("Test 14", 14),
            new Person("Test 15", 15),
            new Person("Test 16", 16),
            new Person("Test 17", 17),
            new Person("Test 18", 18),
            new Person("Test 19", 19),
            new Person("Test 20", 19)
         };

         var prizes = SplitPrizeFund(1000, winners.Length);
         AllocatePrizes(winners, prizes);
      }

      private static void AllocatePrizes(IEnumerable<Person> positions, double[] prizes)
      {
         var orderedPositions = positions.OrderBy(f => f.Position).ToArray();

         for (var pos = 0; pos < orderedPositions.Length;)
         {
            var currentPerson = orderedPositions[pos];
            // Find equally placed people (if any)
            var comList = orderedPositions.Skip(pos).Where(f => f.Position == currentPerson.Position).ToList();

            // We should now have one or more people in our list
            var splitWays = comList.Count;

            // Total the prize fund over the places found
            double splitFund = prizes.Skip(pos).Take(splitWays).Sum();

            // Allocate the total winnings equally between winners of this place
            bool first = true;
            foreach (var person in comList)
            {
               if (first)
               {
                  Console.WriteLine($"{person.Name,-20} {(splitFund / splitWays),10:C2}");
                  first = false;
               }
               else
               {
                  // Identify equal placed winners 
                  Console.WriteLine($"{person.Name,-19}= {(splitFund / splitWays),10:C2}");
               }
            }

            pos += splitWays;
         }
      }

      private static double[] SplitPrizeFund(double totalFund, int numberOfPrizes)
      {
         var prizes = new double[numberOfPrizes];
         var remainingFund = totalFund;
         int remainingPrizes = numberOfPrizes;

         // Special handling for top three places
         int pos = 0;
         prizes[pos] = Math.Round(remainingFund * 0.25, 2, MidpointRounding.AwayFromZero);
         pos += 1;
         prizes[pos] = Math.Round(remainingFund * 0.20, 2, MidpointRounding.AwayFromZero);
         pos += 1;
         prizes[pos] = Math.Round(remainingFund * 0.15, 2, MidpointRounding.AwayFromZero);
         pos += 1;
         remainingPrizes -= 3;
         remainingFund -= prizes[0] + prizes[1] + prizes[2];

         // Linear reducing split from 4th (replace this with whatever you want)
         int totalPortions = 0;
         for (int i = 1; i <= remainingPrizes; i++)
            totalPortions += i;

         for (int i = remainingPrizes; i >= 1; i--)
         {
            prizes[pos] = Math.Round(remainingFund * i / totalPortions, 2, MidpointRounding.AwayFromZero);
            remainingFund -= prizes[pos];
            totalPortions -= i;
            pos++;
         }

         return prizes;
      }

Сначала я не понял, что вы сказали, поэтому я изначально проголосовал за этот ответ. Я думаю, что кто-то другой, возможно, сделал то же самое. Надеюсь, я помог немного прояснить, почему это хорошее решение.

Ruzihm 28.05.2019 20:53

Стив, это здорово, но это не работает для 4-5 человек. Если у вас призовой фонд 20 долларов, а 4 человека дают каждому по 5 долларов, это не совсем так. То же самое для 3 человек, каждый получает по 4 доллара, что не составляет сумму призового фонда.

Cypras 19.06.2019 04:31

@Cypras, я спросил об этом ОП, и он сказал, что будет не менее 20 человек. Это был его выбор, а не разделение на места с 1 по 3. Если вам это нужно менее чем для 6 человек, измените функцию SplitPrizeFund.

Steve Todd 19.06.2019 10:59

@Cypras, я вижу, ты был ОП. Применяется тот же пункт. Ваши собственные правила о распределении первых 3-х мест вызывают проблему. Вы можете удалить специальный раздел обработки в SplitPrizeFund, позволив функции генерировать простое линейное уменьшение суммы для каждого места.

Steve Todd 19.06.2019 13:14

Другие вопросы по теме