非重复生成全子集组合排列(含重复数字时,生成不重复全子集组合排列)
2011-09-28 22:15
267 查看
Sample Input
4
1 2 2 3
Sample Output
1
12
122
1223
123
13
2
22
223
23
3
如果采用上篇文章的程序(处理不含重复数),运行的结果是:
以上均为重复数据,上标表示在原数据中使用的是重复数据的第几个数据,这就多出来好几种。
出现这种情况的原因是:在mat中存有重复的数据,在赋值的时候,仍然把这些数据取出直接赋值到数组result中。
要避免这种情况,就引入两个数组mat和 used数组:
mat数组:一个存放不重复数据的数据
used数组:存放每个数据出现的次数
在递归过程中,使用mat为数组result直接赋值。在赋值时,由于使用不重复数据的数据mat数组直接对其进行赋值,这就避免出现121
和122情况了。
但是,使用这种存储的方式,就会把应该出现的数据也给扼杀了,如1223。这里的做法是 递归传值的时候,mat数组中每一位数据可以重复传一次,检测是不是重复出现过。
具体表现是solve(cur_totalVar+1,i)中的i,即下一次取数的下标是i,而i是本次递归刚刚处理过下标i的位置,使用这样的方法,就可以连续的检测某一个数是不是重复出现了,
进而可以连续的读取。
4
1 2 2 3
Sample Output
1
12
122
1223
123
13
2
22
223
23
3
如果采用上篇文章的程序(处理不含重复数),运行的结果是:
以上均为重复数据,上标表示在原数据中使用的是重复数据的第几个数据,这就多出来好几种。
出现这种情况的原因是:在mat中存有重复的数据,在赋值的时候,仍然把这些数据取出直接赋值到数组result中。
要避免这种情况,就引入两个数组mat和 used数组:
mat数组:一个存放不重复数据的数据
used数组:存放每个数据出现的次数
在递归过程中,使用mat为数组result直接赋值。在赋值时,由于使用不重复数据的数据mat数组直接对其进行赋值,这就避免出现121
和122情况了。
但是,使用这种存储的方式,就会把应该出现的数据也给扼杀了,如1223。这里的做法是 递归传值的时候,mat数组中每一位数据可以重复传一次,检测是不是重复出现过。
具体表现是solve(cur_totalVar+1,i)中的i,即下一次取数的下标是i,而i是本次递归刚刚处理过下标i的位置,使用这样的方法,就可以连续的检测某一个数是不是重复出现了,
进而可以连续的读取。
#include <iostream> using namespace std; const int len=10; int n; int num;//不重复的实际个数 int mat[len]; int result[len]; int used[len]; void push(int varNum); void solve(int cur_totalVar,int nextVar); int main() { cin>>n; num=0; int var; for (int i=0;i<n;i++) { cin>>var; push(var); } solve(0,0); system("pause"); return 1; } /*---------------------- 操作的目的:生成一个数据全不重复的数组,并记录每个数出现的次数 操作结果: num记录不重复数的个数(mat数组中数据的长度) mat数组存储不重复的数据 used数组统计对应mat数组位置数据的出现次数 函数参数: varNum:存储刚刚输入的数据,用来检测是不是重复的数据 ------------------------*/ void push(int varNum) { for (int i=0;i<num;i++) { if (mat[i]==varNum) { used[i]++; return; } } mat[num]=varNum; used[num]++; num++; } /*---------------------- 操作的目的:生成全子集组合排列(含重复数据) 初始条件: num记录不重复数的个数(mat数组中数据的长度) mat数组存储不重复的数据 used数组统计对应mat数组位置数据的出现次数 操作结果: 输出全部子集 函数参数: cur_totalVar:针对输出数组result,表示现在要存放数据的位置,之后也控制着输出 nextVar:针对原存储数组mat,表示下一个要读取数据的位置 ------------------------*/ void solve(int cur_totalVar,int nextVar) { for (int i=0;i<cur_totalVar;i++) { cout<<result[i]; } cout<<endl; for (int i=nextVar;i<num;i++) { if (used[i]) { result[cur_totalVar]=mat[i]; used[i]--; solve(cur_totalVar+1,i); /*这里的参数i表示:数组mat中下一个要处理的数是本次函数刚刚处理过的, 这里还要在检查一遍,就是为了处理有数据重复的情况,如果数据不重复,就使用i+1*/ used[i]++;//恢复现场 } } } /* 算法的思想: 函数思想:使用for循环遍历原存储数据的数组mat,边遍历边对输出数组result赋值,同时进行递归. 为了处理重复的数据,就让mat数组存储不重复的数据,在为数组result赋值时,使用这个不重复的数组进行赋值, 但是要处理重复的数据的话,在递归传递参数的时候,把刚刚处理过的数据再传进去一遍,在进行一下处理,检测是不是有重复,若重复,就可以再使用一次。但是这里的重复使用时不会出现重复的数据的,具体可以写一下递归的过程分析一下。其中还是数组mat起了关键作用。 忽略递归,从for循环来看,存储数组中要存放数据的位置cur_totalVar是固定的,使用for循环对result进行赋值, 这样就可以让输出数组中同一个位置有多个变化的变量。这时,在看递归,当结果数组的cur_totalVar位置已经赋值成功后, 之后应该是对结果数组result的cur_totalVar+1的位置使用原数组mat的i+1位置的数据进行赋值(第i个数据已经赋过值了)--这里先不考虑重复数据。 如果考虑重复的位数,当然应该是传入mat中第i位,看是不是重复。*/
相关文章推荐
- 非重复组合排列(含重复数字时,生成不重复组合排列)
- 递归求解几类排列组合问题(六、非重复生成全子集组合排列)
- C语言算法—(生成子集的升级)生成数据的全部组合(含重复数字)(类似建立树的回溯法)
- sql 生成8位字母数字组合不重复随机码
- 递归学习_组合_生成全子集组合排列(不含空集)
- 递归求解几类排列组合问题(五、生成全子集组合排列)
- 福彩双色球中红球由6个1-33之间的数字组合,且不重复,编写代码,使用Set集合来存储随机生成的1-33的数字,然后输出生成的数字
- 【组合+全排列】补充上篇【如何打印没有重复数字的自然数字列表?】
- python无限生成不重复(字母,数字,字符)组合
- 排列组合,子集生成问题,与nyoj 组合数
- java生成随机数字和字母组合
- 随机生成几位数字字母组合
- 【小程序】JAVA实现从10~50中随机生成50个数,统计出现的数字及次数,输出出现最多的次数及对应的数字,按数字升序排列。
- 12个字母任选5个进行排列组合,不可重复 javascript 递归实现
- 重复数字的组合
- 回溯实现数字的排列组合
- 数字组合不重复的算法
- (转)php排列组合 1到9数字相加都等于20
- 回溯法解决 排列组合问题 全排 选排 可重复 不可重复
- 根据时间随机生成12位数字,且不重复2015-8-21