摘要
将n个数字放到一个长度为n的数组中。
再生成一个长度为n的0-1数组,1代表选取该位置映射的元素,0代表不选取(1的总数等于m),通过枚举0 1的所有位置,来完成数字组合的枚举。
具体枚举逻辑:
令0-1数组所有元素都为0
令0-1数组前m个元素都为1(此时就已经代表了一种组合)
循环切换:
利用for找到该0-1数组第一个存在“1 0”的位置(即前一位置为1,后一位置为0),对调两者位置(变为0 1),再将该位置之前的所有1移动到数组最左边。 此时完成一次新组合。
当数组中的m个一,连续排放在该z数组的最右边的,就是最后一次组合,结束循环。
实例:
例如求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
代码(未整理,但其中做了01转换)
int compare(int this_value, int new_ar[], int new_len) {//输入当前目标值,输入去除该值后的数组,给出新数组长度,返回该值是否可以被数组中两个数累加
int this_sum, counter;
int *bl = new int[new_len];
counter = 0;
for (int i = 0; i < new_len; i++) bl[i] = 0;
bl[0] = 1;
bl[1] = 1;
while (1) {
this_sum = 0;
for (int i = 0; i < new_len; i++) if (bl[i] == 1) this_sum += new_ar[i];
if (this_sum == this_value) {//如果满足了,break
counter = 1;
break;
}
if (bl[new_len - 1] == 1 && bl[new_len - 2] == 1) break; //如果刚刚做的是最后一次组合,break
//生成下一次组合
int i0;
for (i0 = 0; i0 < new_len; i0++) //找出第一个10,对调
if (bl[i0] == 1 && bl[i0 + 1] == 0) {
bl[i0] = 0;
bl[i0 + 1] = 1;
break;//第一个10,发现位置的索引就是此时i0
}
for (int i1 = 0, i2 = 0; i1 < i0; i1++) {//将i0前面的1全部放到开头,
if (bl[i1] == 1) {//原来的位置改0,从开头把1放过去
bl[i1] = 0;
bl[i2++] = 1;
}
}
}