用重复生成集合元素的k组合的算法?

时间:2012-09-18 10:30:21

标签: c algorithm combinations

我正在寻找一种算法,该算法将一组两个元素T = {0, 1}k作为输入,并生成所有k - T的组合,如下所示:

000
001
010
011
100
101
110
111

k很小时,可以直接实现迭代,如上例中的k=3。任何想法如何设计递归算法,以便算法独立于k

5 个答案:

答案 0 :(得分:6)

你可以递归地做。假设这是一种学习练习,我会给你伪代码而不是C程序:

generate (int pos, int element[T], int current[N])
    if pos == N
        print (current)
        return

    for i : 0..T
        current[pos] = element[i]
        generate(pos+1, element, current)

end

前三行是基本情况。 pos从零开始,并指示current数组中需要由当前递归调用级别填充的位置。 pos到达N后,我们会打印当前组合并返回到先前级别。

底部的三行是一个循环,类似于k=3时问题解决方案中的嵌套循环。 "嵌套"通过递归动态发生:您可以将递归调用的下一级别视为另一级别的循环嵌套"。从本质上讲,递归解决方案允许您构建N嵌套循环,其中N仅在运行时才知道。

答案 1 :(得分:2)

你不需要递归算法。如果查看列表,您应该看到“模式”。

这是从0到2 ^ k-1的二进制数。因此,简单的解决方案就是计算。

for (i = 0; i < (1<<k); i++) {
    // generate the binary representation of i
    for (c = k-1 ; c >= 0; c--) {
       r = i >> c;
       printf((r & 1) ? "1" : "0");
    }
    printf("\n");
}

编辑:如果你需要一个递归的apporach,你可以通过递归长度轻松地做到这一点,我给出一些伪代码(因为在我看来,递归只有当它是某些分配时才有意义/做作业,然后你应该自己做点什么):

print_all_combos(int k, char* prefix) {
   if (k == 0) {
      printf("%s\n", prefix);
      return;
   }
   append(prefix, "0");
   print_all_combos(k - 1 , prefix);
   remove_last_char(prefix);
   append(prefix, "1");
   remove_last_char(k - 1, prefix);
}

并用k和空字符串作为参数调用它。

答案 2 :(得分:1)

如果您在设计时知道k,则很容易使用k循环生成所有k组合,即如果您想要所有4组合,则可以使用4个循环来完成:

for c1=0 to 1
  for c2=0 to 1
    for c3=0 to 1
      for c4=0 to 1
        print c1,c2,c3,c4

如果您在设计时不知道k,则需要一种模拟k循环的方法。这很容易,创建一个大小为k的数组并在索引i处存储ci的当前值(循环数i索引)。

c : array[1..k]
fill(c,0) // initialize all the cells with 0
do 
  for i=1 to k
    print c[i]
while increment(c) // get next values

increment获取下一个值,如果已经使用了所有值,则返回false,否则返回true。

increment(c : array[1..k])
begin
  i=k
  do
    c[i]=c[i]+1;
    if c[i]=2 // i.e. MAX+1
      c[i]=0
      i=i-1 // incerment previous position
    else
      return true // increment done
    end if
  while (i>1)

  // here we need to increment the first position
  c[i]=c[i]+1
  if c[i]=2 // we looped thru all the values
    c[i]=0
    return false
  end if
  return true
end

此方法可以推广到任何 base 中的任何循环(=每个循环的不同最大值)或具有不同的起始值,步骤等... 这种方法也可以推广用于生成重复的词典组合等...谷歌里程表或看看TAOCP Knuth第3卷第2和第3章。

答案 3 :(得分:0)

根据您提供的示例,我认为您指的是k-permutations,而不是组合。引自维基百科:

  

组合是一种从较大的群体中选择一些东西的方式,其中(与之不同)   排列)顺序无所谓。

答案 4 :(得分:0)

#include<stdio.h>
#include<conio.h>
void calAns(int idx, int f[3]);
int main()
{
    int f[3];
    calAns(0,f);
    getch();
    return 0;
}

void calAns(int idx, int f[3])
{
    if(idx == 3)
    {
        int i;
        for(i = 0; i<3; i++)
            printf("%d",f[i]);
        printf("\n");
        return;
    }

    f[idx] = 0;
    calAns(idx+1, f);
    f[idx] = 1;
    calAns(idx+1, f);
}