主题用算组合的方法也可以。
这个是用“换位法”算组合。
示例:
/*
从n个数中取出m个数的组合(换位法)
思路:
1、用一个数组c[n],数组元素的值为1表示其代表的数被选中,为0则没选中。
2、先将数组c[n]前m个元素初始化为1,表示第一个组合为前m个数。
3、之后从左到右扫描数组c[n],当找到第一个c[i]和c[i+1]元素值为“1和0”组合时,将其变为“0和1”组合(取反)。
同时将其(c[i])左边的所有“1”全部移动到数组c[n]的最左端。
4、如果找不到“1 0”组合,即m个“1”全部移动到最右端时,就得到了最后一个组合。
例如求5中选3的组合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5
*/
#include <stdio.h>
#include <stdlib.h>
int _factorial(n)
//阶乘
{
int i, ret=1;
for (i=2; i<=n; i++)
ret *= i;
return ret;
}
int _cnm(int n, int m)
//组合数
{
//C(n,m) = n!/m!(n-m)! = C(n,n-m)
return _factorial(n)/(_factorial(m)*_factorial(n-m));
}
void _print(int *a, char *c, int n) //打印一组
{
int i;
for (i=0; i<n; i++)
if (c[i] == 1)
printf("%d ", a[i]);
printf("\n");
}
void _combine(int *a, int n, int m)
{
int i, j, k;
//用一个数组c[n],数组元素的值为1表示其代表的数被选中,为0则没选中。
char *c=(char *)calloc(n, sizeof(char));
//先将数组c[n]前m个元素初始化为1,表示第一个组合为前m个数。
for (i=0; i<m; i++)
c[i] = 1;
while (1)
{
//打印一组
_print(a, c, n);
//之后从左到右扫描数组c[n],找到第一个c[i]和c[i+1]元素值为“1和0”组合。
for (i=0; i<n-1; i++)
if (c[i]==1 && c[i+1]==0)
break;
//如果找不到“1 0”组合,即m个“1”全部移动到最右端时,就得到了最后一个组合。
if (i==n-1)
break;
//找到第一个c[i]和c[i+1]元素值为“1和0”组合时,将其变为“0和1”组合(取反)。
c[i] = 0;
c[i+1] = 1;
// 同时将其(c[i])左边的所有“1”全部移动到数组c[n]的最左端。
for (j=0; j<i && c[j]==1; j++) NULL;
for (k=j,j++; j<i; j++)
if (c[j] == 1)
{
c[k++] = 1;
c[j] = 0;
}
}
free(c);
}
main()
{
int a[]={1,2,3,4,5};
int n=sizeof(a)/sizeof(int);
int m;
for (m=0; m<n; m++)
printf("%d ", a[m]);
m = 3;
printf("\nn = %d, m = %d\n", n, m);
printf("C(n,m) = C(%d,%d) = %d\n", n, m, _cnm(5, m));
_combine(a, n, m);
}