C#查找所有可能的数字组合

时间:2016-04-05 19:39:00

标签: c# algorithm permutation

我正在努力制作算法" shuffles"一组数字以这样的方式从0开始按升序排序,下一个数字不得超过前一个+ 1,它们的长度也必须为15,并且必须包含数字集中的每个数字。例如,如果我们有数字:

  

0,1

所需的输出是:

  

0,0,0,0,0,0,0,0,0,0,0,0,0,0,1(是的,这是14个零)

     

0,0,0,0,0,0,0,0,0,0,0,0,0,1,1

     

...

     

0,1,1,1,1,1,1,1,1,1,1,1,1,1,1

如果数字是

,也一样
  

0,1,2

     

0,0,0,0,0,0,0,0,0,0,0,0,0,1,2(必须包括每个数字)

我尝试了以下内容,但我失败了:

版本1

private static List<List<int>> GetNumbers(int lastNumber)
    {
        if (lastNumber == 0)
        {
            return new List<List<int>> { new List<int> { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
        }
        int[] setOfNumbers = new int[lastNumber + 1];
        List<List<int>> possibleRoutes = new List<List<int>>().ToList();
        for (int i = 0; i <= lastNumber; i++)
        {
            setOfNumbers[i] = i;
        }
        var temp = new List<int>();
        int[] possibleRoute = new int[15];
        for (int j = 0; j < size - lastNumber; j++)
        {
            possibleRoute[j] = 0;
        }
        for (int j = lastNumber; j < possibleRoute.Length; j++)
        {
            for (int k = j; k > 0; k--)
            {
                possibleRoute[k] = lastNumber - 1;
            }
            for (int i = size - 1; i >= j; i--)
            {
                possibleRoute[i] = lastNumber;
            }
            possibleRoutes.Add(possibleRoute.ToList());
            generalCounter++;
        }
        return possibleRoutes;
    }

版本2

private static List<List<int>> GetNumbers(int lastNumber)
    {
        if (lastNumber == 0)
        {
            return new List<List<int>> {new List<int> {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
        }
        int[] setOfNumbers = new int[lastNumber + 1];
        List<List<int>> possibleRoutes = new List<List<int>>().ToList();
        for (int i = 0; i <= lastNumber; i++)
        {
            setOfNumbers[i] = i;
        }
        var temp = new List<int>();
        int[] possibleRoute = new int[15];
        for (int j = 0; j < size - lastNumber; j++)
        {
            possibleRoute[j] = 0;
        }
        for (int i = 1 ; i <= lastNumber ; i++)
        {
            int newNumber = lastNumber - i;
            for (int k1 = i + 1; k1 <= size; k1++)
            {
                for (int j = possibleRoute.Length - 1; j > k1 - i - 1; j--)
                {
                    possibleRoute[j] = lastNumber;
                }
                for (int k = i; k <= k1 - 1; k++)
                {
                    possibleRoute[k] = newNumber;
                }
                possibleRoutes.Add(possibleRoute.ToList());
                generalCounter++;
            }
        }
        return possibleRoutes;
    }

2 个答案:

答案 0 :(得分:1)

我误解了这个问题。开始这个答案。

让我们以另一种方式陈述问题。

我们有很多项目,十五项。

我们有多个数字,比如说0,1,2。

我们想知道x 0,y和z两个组合是什么,x + y + z = 15,x,y和z都是至少一个。

所以,将它减少到一个更容易的问题。假设有一个零。 现在你可以解决更容易的问题了吗?问题现在变小了:现在的问题是生成长度为14且至少有一个1和一个2&#34;的所有序列。你看到如何解决更容易的问题?

如果没有,请将其分解为更容易的问题。假设有一个1.你能解决这个问题吗?现在的问题是找到所有序列中包含13个2的序列,并且只有其中的一个。

现在假设有两个1。你能解决那里的问题吗?

您是否看到如何使用解决方案解决更难的问题?

答案 1 :(得分:0)

与这样的各种问题一起使用的简单策略是按字典顺序列出可能性。在伪代码中,你会做这样的事情:

  1. 按字典顺序将V设置为第一个可能的序列。

  2. 重复以下步骤:

    • 输出V
    • 如果可能,请按字典顺序将V设置为下一个序列。
    • 如果无法做到,请退出循环。
  3. 对于许多情况,您可以通过在V中向后搜索最右侧的“可递增”值来解决第二个子问题(“将V设置为下一个序列”);也就是说,可以递增的最右边的值导致序列的可能前缀。一旦该值递增(按最小量),您将找到以该前缀开头的最小序列。 (这是第一个子问题的简单概括:“找到最小序列”。)

    在这种情况下,这两个子问题都很简单。

    • 如果值不是集合中的最大数字,则它是可递增的,并且它与前面的值相同。它只能递增到集合中的下一个更大的值。

    • 要查找以k结尾的前缀开头的最小序列,首先要查找集合中大于k的所有值,并在结尾处按顺序排列的序列。然后使用k填写前缀(如果有)之后的其余值。

    要将此方法应用于不同的枚举问题,请参阅https://stackoverflow.com/a/30898130/1566221。它也是next_permutation标准实现的本质。