ACM之递归组合【递归很重要 】
递归求解几类排列组合问题
西南交通大学吴汉舟2009年
Welcome to JudgeOnline
对于搜索的深度很深或深度不固定的情况,则无法用枚举的方法来设置循环嵌套的层数,这时可以考虑用递归法来完成搜索任务。递归是一种常用算法,它是搜索的另一种实现方式。如果在算法设计中采用一个函数或过程直接或间接地调用它自身来解决问题的方法,则称该方法为递归算法。递归算法必须要设计好一个或若干个确定的递归终止条件。
一、类循环组合排列
Sample Input:
4 2
Sample Output
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
//Program
#include
int n,m;
int mat[10];
void solve(int l){
if(l>=n){
for(int i=0;i puts(""); return; } for(int i=0;i mat[l]=i; solve(l+1); } } int main(){ while(scanf("%d%d", &n, &m)!=EOF){ solve(0); } return 0; } 二、全组合排列 Sample Input 3 1 2 3 Sample Output 123 132 213 231 312 321 //Program #include #include const int maxn=11; int n; int used[maxn];//标记数组 int mat[maxn];//存储数组 int num[maxn];//输出数组 void solve(int l){ if(l>=n){ for(int i=0;i puts(""); return; } for(int i=0;i if(!used[i]){ used[i]=1; num[l]=mat[i]; solve(l+1); used[i]=0; } } } int main(){ while(scanf("%d", &n)!=EOF){ for(int i=0;i memset(used,0,sizeof(used)); solve(0); } return 0; } 三、非重复组合排列(含重复数字时,生成不重复组合排列)Sample Input 4 1 2 2 3 Sample Output 1223 1232 1322 2123 2132 2213 2231 2312 2321 3122 3212 3221 //Program #include const int maxn=10; int n,var; int Index; int used[maxn],mat[maxn],num[maxn]; void push(int varNum){ //压栈 for(int i=0;i if(mat[i]==varNum){ ++used[i]; return; } } mat[Index]=varNum; ++used[Index++]; } void solve(int l){ //求解 if(l>=n){ for(int i=0;i puts(""); return; } for(int i=0;i if(used[i]){ used[i]--; num[l]=mat[i]; solve(l+1); used[i]++; } } } int main(){ while(scanf("%d", &n)!=EOF){ Index=0; for(int i=0;i scanf("%d", &var); push(var); } solve(0); } return 0; } 四、普通选择性组合排列Sample Input 5 3 1 2 3 4 5 Sample Output 123 124 125 134 135 145 234 235 245 345 //Program #include const int maxn=10; int totalN,selectM; int mat[maxn];//存储数组 int num[maxn];//输出数组 void solve(int startVar,int selectVar){ if(selectVar>=selectM){ puts(""); return; } for(int i=startVar;i num[selectVar]=mat[i]; solve(i+1,selectVar+1); } } int main(){ while(scanf("%d%d", &totalN, &selectM)!=EOF){ for(int i=0;i solve(0,0); } return 0; } 五、生成全子集组合排列(不含空集) Sample Input 4 1 2 3 4 Sample Output 1 12 123 1234 124 13 134 14 2 23 234 24 3 34 4 //Program #include const int maxn=10; int n; int mat[maxn]; int num[maxn]; void solve(int cur_totalVar,int nextVar){ if(cur_totalVar)puts(""); for(int i=nextVar;i num[cur_totalVar]=mat[i]; solve(cur_totalVar+1,i+1); } } int main(){ while(scanf("%d", &n)!=EOF){ for(int i=0;i solve(0,0); } return 0; } //注意:倘若需要输出空集(也即输出一个换行),可做如下修改 //在函数solve()中,将if(cur_totalVar)puts(""); 改为puts(""); 六、非重复生成全子集组合排列(含重复数字时,生成不重复全子集组合排列)Sample Input 4 1 2 2 3 Sample Output 1 12 122 1223 123 13 2 22 223 23 3 //Program #include const int maxn=10; int n,var; int Index; int used[maxn],mat[maxn],num[maxn]; void push(int varNum){ //压栈 for(int i=0;i if(mat[i]==varNum){ ++used[i]; return; } } mat[Index]=varNum; ++used[Index++]; } void solve(int l,int p){ //求解 for(int i=0;i if(l)puts(""); for(int i=p;i if(used[i]){ used[i]--; num[l]=mat[i]; solve(l+1,i); used[i]++; } } } int main(){ while(scanf("%d", &n)!=EOF){ Index=0; for(int i=0;i scanf("%d", &var); push(var); } solve(0,0); } return 0; } //注意:倘若需要输出空集(也即输出一个换行),可做如下修改 //在函数solve()中,将if(l)puts(""); 改为puts(""); 总结:递归思想在搜索技术中有着广泛的应用,应当熟练掌握和学习这种思想,对求解这一类搜索题目大有裨益。