求组合

从一组n个元素中,寻找任意个组合的所有情况,例如,从 4,5,6,7 这四个元素中,寻找任意3个元素的所有组合,不能重复,

有 4,5,6,

    4,5,7,

    5,6,7 这三种组合。

 

 static void Main(string[] args)
        {
            List<int> lsa = new List<int>();
            lsa.Add(5);
            lsa.Add(6);
            lsa.Add(7);
            lsa.Add(8);
            lsa.Add(9);

            List<int> lsb = new List<int>();
            lsb.Add(0);
            lsb.Add(0);
            lsb.Add(0);
            lsb.Add(0);
            lsb.Add(0);

            List<int> lsc = new List<int>();
            lsc.Add(0);
            lsc.Add(0);
            lsc.Add(0);
            lsc.Add(0);
            lsc.Add(0);
            lsc.Add(0);

            int count = 0;
            for (int i = 0; i < 31; i++)//对于所有的情况进行筛选   注意 31=2的N次方-1
            {
                add(lsb, lsc, lsa.Count);// 对标志数组进行加1
                if (IS(lsb, 3))//判断是否符合要求
                {
                    Console.WriteLine(putout(lsa,lsb));
                }
            }
            Console.ReadLine();
        }

        static void add(List<int> lsb, List<int> lsc, int n)
        {
            int i;
            for (i = 0; i < n + 1; i++)
            {
                lsc[i] = 0;
            }

            lsc[0] = 1;
            for (i = 0; i < n; i++)
            {
                if (lsc[i] == 1)
                {
                    if (lsb[i] == 1)
                    {
                        lsb[i] = 0;
                        lsc[i + 1] = 1;
                    }
                    else lsb[i] = 1;
                }
            }
        }

        static bool IS(List<int> lsb, int n)
        {
            int sum = 0;
            for (int i = 0; i < lsb.Count; i++)
            {
                if (lsb[i] == 1)
                {
                    sum++;
                }
            }
            if (sum == n)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        static string putout(List<int> lsa, List<int> lsb)
        {
            string str = string.Empty;
            for (int i = 0; i < lsb.Count; i++)
            {
                if (lsb[i] == 1)
                {
                    str += lsa[i] + ",";
                }
            }
            return str;
        }

 

参考原文:

这是一个组合的问题,我不会vb但会C++,我用C++编了一个,思想如下,希望对你有所帮助:定义三个数组,a,b,c,都是整形的,a中放你所说的一堆数,b和a的数组长度一样,c比a的长度大1,虽然直接选出所有组合很难,但有一个巧点的方法(来源于集合论),因为b和a数组长度一样,可以有一个对应并系:b[i]---a[i].现规定数组b中和每一个元素只能是0或1,这样,如果我们们从a中选取K个元素,就相当于b中有K个1,n-k个0.(因为b和a之间是一一对应的),如此就有如下算法能选出所有可能的组合:初始化b的所有元素为0,做一个循环,每一次对b进行"加"1,这里的"加"1是像二进制里运算一样,当b[0]=0时,加1后,b[0]变为1,当b[0]=1时,b[0]就变成o了,并且向前进一位,依些类推(就像二进制的加法:0111+1=1000一样,只不过在程序里,0,1是数组b的元素).然后判断b中是否有k个1,如果是,输出那些在b中为1对应的a中的元素(即:如果b[i]=1,则输出a[i],否则就不输出a[i],输出的就是可能的组合之一);循环的次数应该为2^n-1次(即从b中的元素为全0到b中的元素为全1),这样就能输出所有的可能的组合.至于上面提到的数组c,只是起到一个进位标志的做用,辅助完成对b进行"加"1和操作.
我的源代码如下(以从10个元素中选取5个为例)
#include<iostream.h>
void add(int b[],int c[],int n){//对标志数组加1,参数n表示数组的长度
int i;
for(i=0;i<n+1;i++)c[i]=0;
c[0]=1;
for(i=0;i<n;i++){
  if(c[i]==1){
   if(b[i]==1){
    b[i]=0;
    c[i+1]=1;
   }else b[i]=1;
  }
}
}
bool is(int b[],int k){//判断此时的组合是否符合要求
int i;
int sum=0;
for(i=0;i<10;i++){
  if(b[i]==1)sum++;
}
if(sum==k)return true;
else return false;
}
void putout(int a[],int b[],int n){//输出符合要求的数字
int i;
for(i=0;i<n;i++)
if(b[i]==1)cout<<a[i]<<"   ";
cout<<endl;
}

void main(){
int a[10];//这里选的数是10,可以改成任意的你休处理的数n
int b[10];
int c[11];//为了确保数组不会溢出,此数组要比n大1
int i;
int j=0;
for(i=0;i<10;i++){//初始化
  a[i]=i;//这里的a[i]就是你要处理的数,你可以改,只要初始化一下。
  b[i]=0;
}
cout<<a[1];
for(i=0;i<1023;i++){//对于所有的情况进行筛选
  add(b,c,10);// 对标志数组进行加1
  if(is(b,5))//判断是否符合要求
  {
   putout(a,b,10);//符合要求,输出
   j++;//测试用的代码,看总的输出的个数,验证一下,是不是等于C(n,k)这个组个合数
  }
}
cout<<j;
}
我验证了一下,确实是正确的.组合的个数为252个,等于C(10,5).

 

posted @ 2010-03-24 15:21  pjh123  阅读(228)  评论(0)    收藏  举报