从一组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).