指数型枚举: 无个数限制
- 题目描述: 从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
朴素dfs枚举
int n;
vector<int> ans;
void calc(int x) {
if(x == n + 1) {
for(auto c: ans) printf("%d ", c);
puts("");
return ;
}
calc(x + 1);
ans.push_back(x);
calc(x + 1);
ans.pop_back(); // 恢复原始状况
}
void solve() {
scanf("%d", &n);
calc(1);
}
二进制压缩版dfs
int n;
void dfs(int u, int state) { // state 的二进制表示中,选过的数所对应的二进制位为1
if(u == n) { // 从零开始到n - 1结束
for(int i = 0; i < n; i++) {
if(state >> i & 1) printf("%d ", i + 1); // state的二进制表示中为一的表示选中,输出
}
printf("
");
return ;
}
dfs(u + 1, state); // 不选
dfs(u + 1, state | 1 << u); // 选, 并将其置为一
}
void solve() {
scanf("%d", &n);
dfs(0, 0);
}
组合型枚举:有个数限制
- 题目描述: 从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
朴素dfs: 运行时间过长
vector<int> ch;
int a, b;
void calc(int x) {
if(x > a + 1) return ;
if(ch.size() == b) {
for(int i = 0; i < ch.size(); i++) printf("%d ", ch[i]);
printf("
");
return ;
}
ch.push_back(x);
calc(x + 1);
ch.pop_back();
calc(x + 1);
}
void solve() {
scanf("%d%d", &a, &b);
calc(1);
return 0;
}
二进制压缩版dfs
int a, b;
void dfs(int u, int state, int s) {
if(s + a - u < b) return ; // 当前加上剩下的所有的也不满足条件
if(s == b) {
for(int i = 0; i < a; i++) {
if(state >> i & 1) printf("%d ", i + 1);
}
printf("
");
return;
}
dfs(u + 1, state | 1 << u, s + 1); // 选
dfs(u + 1, state, s); // 不选
}
void solve() {
scanf("%d%d", &a, &b);
dfs(0, 0, 0);
}
排列型枚举 ;排列数
- 题目描述:把 1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
朴素版
const int N = 10;
vector<int> ch;
bool st[N];
int n;
void dfs(int u) {
if(u == n + 1) {
for(int i = 0; i < n; i++) printf("%d ", ch[i]);
printf("
");
return ;
}
for(int i = 1; i <= n; i++) {
if(!st[i]) {
ch.push_back(i);
st[i] = true;
dfs(u + 1);
st[i] = false; // 恢复现场
ch.pop_back(); // 恢复现场
}
}
}
void solve() {
scanf("%d", &n);
dfs(1);
return 0;
}
二进制压缩版dfs
- 使用一个32位整型变量,使用其二进制表示数是否被使用, 为1的位表示已经使用
const int N = 10;
vector<int> ch;
int n;
void dfs(int u, int state) {
if(ch.size() == n) {
for(int i = 0; i < n; i++) printf("%d ", ch[i]);
printf("
");
return ;
}
for(int i = 1; i <= n; i++) {
if(!((state >> i) & 1)) {
ch.push_back(i);
dfs(u + 1, state | 1 << i); // 选择该数,置为1
ch.pop_back(); // 恢复现场
}
}
}
void solve() {
scanf("%d", &n);
dfs(1, 1);
return 0;
}
将递归程序转换成非递归程序