【问题标题】:C# dictionary order of combinationsC# 字典的组合顺序
【发布时间】:2012-11-28 05:37:30
【问题描述】:

对于 k 的某些值,我需要在所有 combinations 上迭代从包含 N 个项目的向量 V 中取出 k 个项目。例如,如果 N = 6 和 k = 3,那么我必须在项目 V1、V2 和 V[3] 上调用 F(),然后在项目 V1、V2 和 V[ 上调用 F() 4],以V[4]、V[5]和V[6]结尾。

现在,浏览索引的所有组合很容易。假设 k = 3 和 N = 6。那么第一个元素可以从 1 到 N-(k-1),第二个从 2 到 N-(k-2),第 k 个从 k 到 N(即 N -(k-k))。

因此,对于 k = 3,循环将是:

for (uint a = 1, a <=  N-2, a++)
  for (uint b = a + 1, b <= N-1, b++)
    for (uint c = b + 1, c <= N, c++)
     F(V[a], V[b], V[c])

并且,对于 k = 4,迭代将是:

for (uint a = 1, a <=  N-3, a++)
  for (uint b = a + 1, b <= N-2, b++)
    for (uint c = b + 1, c <= N - 1, c++)
       for (uint d = c + 1, d <= N, d++)
          F(V[a], V[b], V[c], V[d])

然而,问题是:如何在不硬编码(或使用代码生成)的情况下为任意 k 完成 k 级嵌套?

编辑:关于背景(又名这不是家庭作业 :))请参阅 Hans Engler 对我的 Math Stackexchange 问题的回答: 0-1 knapsack like - the set of all non-contained affordable binary selections

编辑:我将提供一个示例。假设 V= {1,2,3,4,5}。

对于 k=2,我希望按以下顺序调用 F:F(1,2), F(1,3), F(1,4), F(1,5), F(2, 3)、F(2,4)、F(2,5)、F(3,4)、F(3, 5) 和 F(4,5)。

对于 k=3,我希望按以下顺序调用 F:F(1,2,3), F(1,2,4), F(1,2,5), F(2,3 ,4,), F(2,3,5), F(3,4,5)

【问题讨论】:

  • 做自己的功课可能意味着你实际上对手头的问题有所了解。#
  • 我必须承认我没有完全理解这个问题,但听起来你需要一个递归函数来解决这个问题。只需传入 k 的值以及循环之间不同的任何其他值。
  • @ChrisBint 我希望我还年轻,甚至可以做作业 :)

标签: combinations


【解决方案1】:

您的代码示例正在生成唯一的组合,而不是排列。无论顺序如何,组合都是唯一的。例如,如果您的数据看起来像这样 - 123、231、321,那么您将使用排列。组合属于二项式系数的范畴。

我用 C# 编写了一个类来处理处理二项式系数的常用函数。它执行以下任务:

  1. 以适合任何 N 选择 K 的格式将所有 K 索引输出到文件。 K-indexes 可以替换为更具描述性的字符串或字母。

  2. 将 K 索引转换为已排序二项式系数表中条目的正确索引。这种技术比依赖迭代的旧已发布技术快得多。它通过使用帕斯卡三角形固有的数学属性来做到这一点。

  3. 将已排序二项式系数表中的索引转换为相应的 K 索引。我相信它也比旧的迭代解决方案更快。

  4. 使用Mark Dominus 方法计算二项式系数,该方法不太可能溢出并且适用于较大的数字。

  5. 该类是用 .NET C# 编写的,并提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用一个名为 InitTable 的 bool 值,当它为 true 时,将创建一个通用列表来保存要管理的对象。如果此值为 false,则不会创建表。无需创建表即可使用上述 4 种方法。提供访问器方法来访问表。

  6. 有一个关联的测试类显示如何使用该类及其方法。它已经过 2 个案例的广泛测试,没有已知的错误。

要了解该课程并下载代码,请参阅Tablizing The Binomial Coeffieicent

以下代码将按顺序遍历这组组合:

int N = 6;  // Total number of elements in the set.
int K = 3;  // Total number of elements in each group.
int[] V = new int[N]; // Holds the vector of numbers.
// Create the bin coeff object required to get all
// the combos for this N choose K combination.
BinCoeff<int> BC = new BinCoeff<int>(N, K, false);
int NumCombos = BinCoeff<int>.GetBinCoeff(N, K);
int[] KIndexes = new int[K];
// Loop thru all the combinations for this N choose K case.
for (int Combo = 0; Combo < NumCombos; Combo++)
{
   // Get the k-indexes for this combination.
   BC.GetKIndexes(Loop, KIndexes);
   // Do whatever processing with the V array that needs to be done.
   // Code to print the values out in C#:
   String S = V[KIndexes[0]].ToString() + ", " + V[KIndexes[1]].ToString() + ", " + 
      V[KIndexes[2]].ToString();
   Console.WriteLine(S};
}

您应该能够相当轻松地将此类移植到您选择的语言。您可能不必移植类的通用部分来实现您的目标。根据您使用的组合数量,您可能需要使用大于 4 字节整数的字长。

【讨论】:

  • 很好的答案:理论解释 + 实际有效的代码。它没有按我的需要排序,而且我还没有弄清楚将帕斯卡三角形转换为组合的魔力(链接的文章都是关于扑克的,我不玩)但我会管理的。谢谢!
【解决方案2】:

这确实有点像作业,which is ok,但你应该指出这是作业。

无论如何,当您看到自己陷入一系列没有明确结束的循环时,递归可能会有所帮助。考虑下面的课程。我将把函数 F() 的内容留空,但为您指明一条合理的路径(我认为):

class Program
{
    private void F(int[] vector, int k)
    {
        if (vector.Length > 0)
        {
            // TO DO: operate on the first k elements of vector
            // Question: what conditions will throw an exception?
            Console.WriteLine("now operating on vector of length: " + vector.Length);

            // Re-define vector and re-apply F()
            vector = vector.Skip(1).Take(vector.Length - 1).ToArray();
            F(vector, k);
        }

    }


    static void Main(string[] args)
    {
        int[] vector = { 0, 1, 1, 2, 3 };
        int k = 3;

        try
        {
            Program p = new Program();
            p.F(vector, k);
        }
        catch (Exception ex)
        {

            Console.WriteLine("Unhandled exception: " + ex.Message);
            System.Environment.Exit(1);
        }
        finally
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.Write("Any key to continue...");
                Console.ReadKey();
            }
        }
    }
}

【讨论】:

  • 不是作业,不是作业。有关完整的现实问题描述,请参阅数学 stackexchagne 的链接。好的,所以我又老又生疏了,但是把这门课称为“家庭作业”有点过分了。
  • 好的,有点自我节省的重新格式化。我会留下作业免责声明,以免退伍军人杀了我。
  • 太棒了。你能看看我的编辑,描述所需的调用序列吗?我不确定这个问题是否足够清楚......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多