帮助数学/编码一组的可能组合来弥补总数 - C#

时间:2010-07-11 13:44:13

标签: c# math

我有一个编码/数学问题,我需要帮助翻译成C#。这是一个扑克筹码计算器,可以获取BuyIn,玩家数量以及每种颜色(有x种颜色)的筹码总量及其价值。

然后它会向您显示每个人可能的筹码组合,以等于买入。然后,用户可以选择他们想要使用的芯片组分发。最好用一个简单的例子来说明。

  • 买入:$ 10
  • 玩家人数:1
  • 10个红色芯片,价值1美元
  • 10个蓝色芯片,价值2美元
  • 10片绿色芯片,价值5美元

所以,可能的组合是:

R / B / G

  • 10/0/0
  • 8/1/0
  • 6/2/0
  • 5/0/1
  • 4/3/0
  • 2/4/0
  • 1/2/1

我花了很多时间试图在C#/ .NET中提出一个算法来解决这个问题。我对可变因素感到磕磕绊 - 一组中通常只有3或4种不同的芯片颜色,但可能有任何数量。如果您有多个玩家,则必须在TotalChips / NumberOfPlayers之前计算。

我开始通过所有芯片的循环,然后从0循环到NumberOfChips以获得该颜色。这几乎是我花了4个小时的时间...我如何编写代码来循环x芯片数量并检查芯片总和的值,如果它等于BuyIn则将其添加到集合中?我需要彻底改变我的方法...

有人能让我走上正确的道路,如何解决这个问题吗?伪代码可以工作 - 感谢您的任何建议!

以下是我到目前为止的尝试 - 它是没有希望的(并且不会编译,只是一个例子向你展示我迄今为止的思考过程) - 最好不要看它,因为它可能会让你对解决方案产生偏见......

   private void SplitChips(List<ChipSuggestion> suggestions)
    {

        decimal valueRequired = (decimal)txtBuyIn.Value;
        decimal checkTotal = 0;
        ChipSuggestion suggestion;

        //loop through each colour
        foreach (Chip chip in (PagedCollectionView)gridChips.ItemsSource)
        {
                //for each value, loop through them all again
                foreach (Chip currentChip in (PagedCollectionView)gridChips.ItemsSource)
                {
                    //start at 0 and go all the way up
                    for (int i = 0; i < chip.TotalChipsInChipset; i++)
                    {
                        checkTotal = currentChip.ChipValue * i;

                        //if it is greater than than ignore and stop
                        if (checkTotal > valueRequired)
                        {
                            break;
                        }
                        else
                        {
                            //if it is equal to then this is a match
                            if (checkTotal == valueRequired)
                            {
                                suggestion = new ChipSuggestion();
                                suggestion.SuggestionName = "Suggestion";

                                chipRed.NumberPerPlayer = i;
                                suggestion.Chips.Add(chipRed);

                                chipBlue.NumberPerPlayer = y;
                                suggestion.Chips.Add(chipBlue);

                                chipGreen.NumberPerPlayer = 0;
                                suggestion.Chips.Add(chipGreen);

                                //add this to the Suggestion
                                suggestions.Add(suggestion);
                                break;
                            }


                    }
                }
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

这是一个实现,它读取芯片数量,芯片(它们的价值和金额)以及购买量,并以您的示例格式显示结果。我已经通过评论对其进行了解释,如果您有任何问题请与我联系。

class Test
{
    static int buyIn; 
    static int numChips;
    static List<int> chips = new List<int>(); // chips[i] = value of chips of color i
    static List<int> amountOfChips = new List<int>(); // amountOfChips[i] = number of chips of color i

    static void generateSolutions(int sum, int[] solutions, int last)
    {
        if (sum > buyIn) // our sum is too big, return
            return;

        if (sum == buyIn) // our sum is just right, print the solution
        {
            for (int i = 0; i < chips.Count; ++i)
                Console.Write("{0}/", solutions[i]);
            Console.WriteLine();

            return; // and return
        }

        for (int i = last; i < chips.Count; ++i) // try adding another chip with the same value as the one added at the last step. 
                                                 // this ensures that no duplicate solutions will be generated, since we impose an order of generation
            if (amountOfChips[i] != 0)
            {
                --amountOfChips[i]; // decrease the amount of chips
                ++solutions[i]; // increase the number of times chip i has been used

                generateSolutions(sum + chips[i], solutions, i); // recursive call

                ++amountOfChips[i]; // (one of) chip i is no longer used
                --solutions[i]; // so it's no longer part of the solution either
            }
    }

    static void Main()
    {
        Console.WriteLine("Enter the buyin:");
        buyIn = int.Parse(Console.ReadLine());
        Console.WriteLine("Enter the number of chips types:");
        numChips = int.Parse(Console.ReadLine());
        Console.WriteLine("Enter {0} chips values:", numChips);
        for (int i = 0; i < numChips; ++i)
            chips.Add(int.Parse(Console.ReadLine()));

        Console.WriteLine("Enter {0} chips amounts:", numChips);
        for (int i = 0; i < numChips; ++i)
            amountOfChips.Add(int.Parse(Console.ReadLine()));

        int[] solutions = new int[numChips];

        generateSolutions(0, solutions, 0);
    }
} 
  

输入buyin:
  10个
  输入芯片类型数量:
  3
  输入3个筹码值:
  1
  2
  5
  输入3个筹码金额:
  10个
  10个
  10个
  10/0/0 /
  8/1/0 /
  6/2/0 /
  5/0/1 /
  4/3/0 /
  3/1/1 /
  2/4/0 /
  1/2/1 /
  0/5/0 /
  0/0/2 /

答案 1 :(得分:2)

通过芯片种类的数量递归地解决问题。

对于基本情况,有多少种方式可以用零筹码进行$ X买入?如果X为零,则有一种方法:没有芯片。如果X大于零,则没有办法做到这一点。

现在我们需要解决N种芯片的问题,给出N-1的解决方案。我们可以采用一种芯片,并考虑该芯片的每个可能数量直到买入。例如,如果筹码为2美元,买入费为5美元,请尝试使用0,1或2。对于这些尝试中的每一次,我们必须仅使用剩余的N-1个筹码来弥补剩余的值。我们可以通过执行递归调用来解决这个问题,然后将我们当前的芯片添加到它返回的每个解决方案中。

private static IEnumerable<IEnumerable<Tuple<Chip, int>>> GetAllChipSuggestions(List<Chip> chips, int players, int totalValue)
{
    return GetAllChipSuggestions(chips, players, totalValue, 0);
}

private static IEnumerable<IEnumerable<Tuple<Chip, int>>> GetAllChipSuggestions(List<Chip> chips, int players, int totalValue, int firstChipIndex)
{
    if (firstChipIndex == chips.Count)
    {
        // Base case: we have no chip types remaining
        if (totalValue == 0)
        {
            // One way to make 0 with no chip types
            return new[] { Enumerable.Empty<Tuple<Chip, int>>() };
        }
        else
        {
            // No ways to make more than 0 with no chip types
            return Enumerable.Empty<IEnumerable<Tuple<Chip, int>>>();
        }
    }
    else
    {
        // Recursive case: try each possible number of this chip type
        var allSuggestions = new List<IEnumerable<Tuple<Chip, int>>>();
        var currentChip = chips[firstChipIndex];
        var maxChips = Math.Min(currentChip.TotalChipsInChipset / players, totalValue / currentChip.ChipValue);
        for (var chipCount = 0; chipCount <= maxChips; chipCount++)
        {
            var currentChipSuggestion = new[] { Tuple.Create(currentChip, chipCount) };
            var remainingValue = totalValue - currentChip.ChipValue * chipCount;
            // Get all combinations of chips after this one that make up the rest of the value
            foreach (var suggestion in GetAllChipSuggestions(chips, players, remainingValue, firstChipIndex + 1))
            {
                allSuggestions.Add(suggestion.Concat(currentChipSuggestion));
            }
        }
        return allSuggestions;
    }
}

答案 2 :(得分:1)

对于某些大型组合,这可能无法在有限时间内解决。 (这是一个NP问题)

http://en.wikipedia.org/wiki/Knapsack_problem

还有代码的链接?这可以帮助你。 希望这有点帮助。