Если бы у меня было 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%, затем остальное делится между оставшимися людьми, при этом люди с одинаковым баллом получают одинаковую сумму.
Что должно произойти, чтобы люди, получившие равные первые равные? Они не должны получать меньше, чем кто-либо другой, но и не должны удваивать сумму первого приза.
Первое место получит 25% от общего призового фонда. Второе место получает 20%, а третье место получает 15%, затем остальное делится между оставшимися людьми, при этом люди с одинаковым баллом получают одинаковую сумму.
а что делать, если есть два усталых для первого? они делят 25% или каждый получает по 25%?
Вы ожидаете, что они разделят между собой суммы 1-го и 2-го места ((25% + 20%)/2), что оставит 3-е и последующие места без изменений. Кипрас, однако, устанавливает здесь правила.
Я не знаю, как лучше всего поступить с этим, потому что если 4 приравняют первое место, это будет весь призовой фонд. Но если мы разделим его, у них может оказаться меньше пользователей, чем более низкие.
В спецификации все еще есть дыры. А если меньше 6 человек? 4-й получит больше, чем 1-й, если их всего 4, и больше, чем 2-й, если их 5.
Будет минимум 20 человек
Это не дубликат, потому что первый вопрос был об ошибке цикла, а этот касается обеспечения того, чтобы возникновение ничьих не нарушало то, что каждый участник с более низким результатом должен получить меньший приз, чем любой один участник с более высоким результатом.
@Cypras помнишь меня из исходного вопроса? У меня есть ответ на этот вопрос, я не шучу, но я не могу его предоставить, потому что он помечен как дубликат. Порекомендуйте изменить заголовок вопроса на что-то «Распределение призового фонда в процессе», чтобы его можно было открыть повторно, потому что люди (не ботинки) ищут по заголовку при переполнении стека любые совпадения, но они не читают вопрос!
@SilentTremor Хорошая идея, я пошел дальше и изменил название
Как я могу пометить его как не дублирующийся?
Я поставлю другой ответ на оригинал.
Вы можете закрыть этот
Это может быть решением:
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 хочет организовать призовую иерархию. Как вы можете предложить решение, если проблема не определена должным образом?
Проблема для меня ясна, он хочет распределить призы в зависимости от ранга пользователя. Чем больше у пользователя очков, тем больше пользователь зарабатывает. Я не понимаю, почему мы не можем понять проблему.
Даст ли это пользователям с одинаковым количеством очков один и тот же приз, сохранив при этом общий призовой фонд? Похоже, так и будет.
Да. Но я должен изменить свой код, чтобы сохранить проценты для первых 3 мест.
Есть ли способ отделить 3 лучших ранга и дать им 25, 20, 15 процентов от общего призового фонда, а затем передать оставшийся призовой фонд остальным людям?
Стив Тодд, голосование только за понижение бесполезно.
Да, я модифицирую свой код, я собираюсь опубликовать модификацию.
Как код будет обрабатывать несколько победителей, занявших первое место, если они набрали одинаковые баллы?
Это действительно умный способ обработки первых, вторых и третьих мест, как вы думаете, вы могли бы показать это в своем коде, как бы вы справились с этим? Многому учимся у вас!
Я собираюсь попытаться изменить свой код.
Я бы сделал это, сначала разделив призовые фракции и определив, какие призы должны быть объединены из-за ничьей. Затем суммируйте объединенные дроби и разделите эту объединенную сумму поровну на всех связанных участников.
Это гарантирует, что сумма, полученная для каждого равного участника, будет меньше или равна наибольшей сумме приза, объединенной в одну, и больше или равна наименьшей сумме объединенного приза.
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;
}
Сначала я не понял, что вы сказали, поэтому я изначально проголосовал за этот ответ. Я думаю, что кто-то другой, возможно, сделал то же самое. Надеюсь, я помог немного прояснить, почему это хорошее решение.
Стив, это здорово, но это не работает для 4-5 человек. Если у вас призовой фонд 20 долларов, а 4 человека дают каждому по 5 долларов, это не совсем так. То же самое для 3 человек, каждый получает по 4 доллара, что не составляет сумму призового фонда.
@Cypras, я спросил об этом ОП, и он сказал, что будет не менее 20 человек. Это был его выбор, а не разделение на места с 1 по 3. Если вам это нужно менее чем для 6 человек, измените функцию SplitPrizeFund.
@Cypras, я вижу, ты был ОП. Применяется тот же пункт. Ваши собственные правила о распределении первых 3-х мест вызывают проблему. Вы можете удалить специальный раздел обработки в SplitPrizeFund, позволив функции генерировать простое линейное уменьшение суммы для каждого места.
я думаю, что алгоритм будет зависеть от того, насколько сильно должен варьироваться приз, т.е. получает ли первое место дважды второе место или значение 2-го места + 10 или 10% больше