【问题标题】:C# Finding all possible combinations of numbers [closed]C#查找所有可能的数字组合[关闭]
【发布时间】:2016-04-06 23:03:21
【问题描述】:

我正在努力制作“洗牌”一组数字的算法,使它们从 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;
    }

【问题讨论】:

  • 你能证明你到目前为止所做的尝试吗?
  • 现在您能解释一下您遇到的具体问题吗?什么不工作?请记住,本网站上的人是真实的人,他们在没有您告诉我们的情况下很难猜出您的想法。我们不会只看一眼你的代码就能看出它有什么问题,也不会把它“带回我们的办公桌”并花几个小时试图弄清楚如何让它工作。这个网站是关于具体的问题的。
  • 好吧,代码完全被破坏了,那里有不止一个问题,老实说,我期待一种与我不同的方法,我真的没有人使用我的代码,因为它太糟糕了,我仍然是初学者,我发布它只是为了向您展示我已尽我所能但无法使其发挥作用。

标签: c# algorithm permutation


【解决方案1】:

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

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

我们有许多项目,十五个。

我们有许多数字,比如 0、1、2。

我们想知道 x 0、y 1 和 z 2 的组合是什么,使得 x + y + z = 15 并且 x、y 和 z 都至少为一。

所以,把它简化为一个更简单的问题。假设有一个零。 现在你能解决更简单的问题吗? 现在问题变小了:问题现在是“生成所有长度为 14 且至少有一个 1 和一个 2 的序列”。你知道如何解决更简单的问题吗?

如果不是,请将其分解为更简单的问题。假设有一个 1. 你现在能解决问题吗?现在的问题是找出所有包含 13 个 2 的序列,而其中只有一个。

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

你知道如何使用解决更简单问题的方法来解决更难的问题吗?

【讨论】:

  • 据我了解,您建议我创建一个列表,其中包含所有当前已知解决方案的特定长度,而不是递归地添加更多内容。我可能完全错了,但即使我不是,我也不知道如何实现它..
  • @KOPEUE:此时不要担心列表等实现细节。你需要能够在纸上解决小版本的问题。写下所有长度为 3 的解,例如从数字 0、1、2 中得出。他们不是很多。现在,给定解决方案列表,描述如何将其转换为长度为 4 的解决方案列表。先用手解决问题,从而深入了解如何用计算机解决问题。
  • @KOPEUE:在这里,我将为您举一个例子。
  • 严格来说,这不是一个解决方案,因为原始问题要求“必须包含数字集中的每个数字”(即序列中的第一个数字需要为 0,假设集合包括一个 0。)所以递归需要包括起始值以及结束值和集合的大小。
  • 一件事@EricLippert 所有的组合都必须以 0 开头并包括所有数字 0 2 违反规则,因为 2 > 0 + 1
【解决方案2】:

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

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

  2. 重复以下操作:

    • 输出 V
    • 如果可能,将 V 设置为按字典顺序排列的下一个序列。
    • 如果不可能,请退出循环。

在许多情况下,您可以通过在 V 中向后搜索最右边的“可增加”值来解决第二个子问题(“将 V 设置为下一个序列”);也就是说,可以递增的最右边的值会导致序列的可能前缀。一旦该值增加(最小数量),您就会找到以该前缀开头的最小序列。 (这是第一个子问题的简单概括:“找到最小序列”。)

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

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

  • 要找到以k 结尾的前缀开头的最小序列,首先要找到集合中大于k 的所有值,并将它们按顺序放在序列的末尾。然后用k 填写前缀(如果有)后面的其余值。

有关将这种方法应用于不同的枚举问题,请参阅https://stackoverflow.com/a/30898130/1566221。也是next_permutation标准实现的精髓所在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多