1、递归实现排列型枚举:
从 1~n 这n(n < 20)个整数中随机选取任意多个,输出所有可能的选择方案。
递归求解:这等价于每个整数可以选或者不选,所有可能的总数共有 2^n种。在每次递归中分别尝试某个数选或不选两条分支,将尚未确定的整数数量-1,从而转化为一个规模更小的同类问题。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <vector>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=1005;
int n;
vector<int> chosen;
void calc(int x){
if(x==n+1){
for(int i=0;i<chosen.size();i++){
printf("%d ",chosen[i]);
}
printf("\n");
return ;
}
//不选x分支
calc(x+1);//求解子问题
chosen.push_back(x);//记录x已被选择
calc(x+1);//求解子问题
chosen.pop_back();//准备回溯到上一问题之前,还原现场
}
int main(){
scanf("%d",&n);
calc(1) ;
return 0;
}
2、递归实现组合型枚举:
从 1~n 这n(n < 20)个整数中随机选取m个,输出所有可能的选择方案。
我们只需在上面指数型枚举的程序calc函数的开头加上以下这条语句即可。
if(chosen.size() > m || chosen.size() + (n-x+1) < m){
return ;
}
这就是所谓的“剪枝”。寻找表换路线其实就是搜索的过程,如果能够及时确定当前问题一定是无解的,就不需要到达问题边界才返回结果。
3、递归实现排列型枚举:
把1~n这 n(n < 20) 个整数排成一行后随机打乱顺序,输出所有可能的次序。
该问题也被称为全排列问题,所有可能的方案总数有 n! 种。在每次递归中,我们尝试把每个可用的数作为数列中的下一个数,求解“把剩余的n-1个整数按照任意次序排列”这个规模更小的子问题。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=1005;
int n;
int order[20] ;
bool chosen[20];//标记被选择的整数
void calc(int k){
if(k == n+1){
for(int i=1; i <= n; i++){
printf("%d ",order[i]);
}
printf("\n");
return ;
}
for(int i=1; i <= n; i++){
if(chosen[i]) continue;
chosen[i]=true;
order[k]=i;
calc(k+1);
chosen[i]=false;
}
}
int main(){
scanf("%d",&n);
calc(1);
return 0;
}