简单枚举:
一般来说枚举变量比较多的时候,可以查看一下多个枚举变量之间是否有一定的关系,如果有,可以通过枚举其中一个,再依据条件计算其他
枚举变量来减少总的枚举量。
7.1.1 除法、
7.1.2 最大乘积、
7.1.3 分数拆分、
7.1.4 双基回文数。
枚举排列:
7.2.1 生成1~n的所有排列
问题描述:
输入整数n,按照字典序从小到大的顺序输出前n个数的所有排列。
解答:
依据思路:先输出1,之后是2~9的全排列,再输出2,之后是1,3~9的全排列...等
可以看出来这里设计递归函数解答比较方便。
我们设计的递归函数需要以下的参数:
(1)已经确定的前缀序列,以便于输出。
(2)需要进行全排列的元素集合,以便依此选择下一位元素。
代码:
/* 按照字典序,依次输出1~n的排列。 */ #include <stdio.h> #include <string.h> #define N 3 /* 这是个错误范例,因为在递归调用时传递参数为数组地址,第一组调用到底部的时候,visit会被全部赋值,而且f也已满,无法回复到之前的状态; void Print(int n,char f[],char visit[]) { //n代表需要加入f中第n个数字, f是已经选择的数;visit是用来选择下一个字符的数组。(visit[i]=='0' 表示i还没被选过。) if(n==N) {f[N]='\0';printf("%s\n",f);} else { //char *a=new char[N+1];char *b=new char[N+1]; for(int i=1;i<N+1;i++) { if(visit[i]=='0')//表明还没被选择过; { visit[i]='1'; f[n]=i+'0'; Print(n+1,f,visit); } }//delete f;delete visit; } } */ //以下使用另外一个标志变量cur来代替visit来完成其“工作”; void Print(int n,int *f,int cur) { //n为最大9 f为当前“前缀”序列,用来输出;cur为标志变量,表明现需要在f[cur]中填写数字; if(n==cur) {for(int i=0;i<9;i++) printf("%d",f[i]); printf("\n");} else { for(int i=1;i<=9;i++) { int ok=1; for(int j=0;j<cur;j++) if(f[j]==i) ok=0; if(ok) {f[cur]=i;Print(n,f,cur+1);} } } } int main() { int f[10]; memset(f,0,sizeof(f)); Print(9,f,0); return 0; }
7.2.2 生成可重集的排列
问题描述:
与7.2.1类似,这里是输出数组A中各元素的所有全排列;
注意点:
1.可以重复
2.防止重复现象。
(两者在代码中的改动之处标明了)
代码:
#include <stdio.h> #include <string.h> #define N 10 int P[N]; void Print(int n,int *P,int *A,int cur) { if(n==cur) {for(int i=0;i<n;i++)printf("%d",A[i]);printf("\n");} else { for(int i=0;i<n;i++) { if(!i || P[i]!=P[i-1])//防止重复 { int a=0,b=0; for(int j=0;j<cur;j++) if(A[j]==P[i]) a++;//可以重复 for(int j=0;j<n;j++) if(P[j]==P[i]) b++; if(a<b) { A[cur]=P[i]; Print(n,P,A,cur+1); } } } } } int main() { int A[N],i,n; printf("请输入数字n:代表数组P中有多少个数字:\n"); while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&P[i]); memset(A,0,sizeof(A)); Print(n,P,A,0); } return 0; }