记录一种从n个数中取m个数进行排列的方法(0-1枚举)

摘要

将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;
 		}
 	}
 } 

你可能感兴趣的:(算法)