DFS
应用
指数型枚举
从
Java
int n;
boolean used = new int[n + 1];
// 尝试选/不选x
void dfs(int x) {
if (x > n) {
for (int i = 1; i <= n; ++i) {
if (used[i]) System.out.print(i + " ");
}
System.out.print("\n");
return;
}
dfs(x + 1);
used[x] = true;
dfs(x + 1);
used[x] = false;
}
// usage: dfs(1)
int n;
boolean used = new int[n + 1];
// 尝试选/不选x
void dfs(int x) {
if (x > n) {
for (int i = 1; i <= n; ++i) {
if (used[i]) System.out.print(i + " ");
}
System.out.print("\n");
return;
}
dfs(x + 1);
used[x] = true;
dfs(x + 1);
used[x] = false;
}
// usage: dfs(1)
C++
int n;
bool used[N];
// 尝试选/不选x
void dfs(int x) {
if (x > n) {
for (int i = 1; i <= n; ++i) {
if (used[i]) printf("%d ", i);
}
return;
}
putchar('\n');
dfs(x + 1);
used[x] = true;
dfs(x + 1);
used[x] = false;
}
// usage: dfs(1)
int n;
bool used[N];
// 尝试选/不选x
void dfs(int x) {
if (x > n) {
for (int i = 1; i <= n; ++i) {
if (used[i]) printf("%d ", i);
}
return;
}
putchar('\n');
dfs(x + 1);
used[x] = true;
dfs(x + 1);
used[x] = false;
}
// usage: dfs(1)
组合型枚举
从
Java
int[] chosen = new int[m];
// 尝试把st...n放在chosen[u]
void dfs(int u, int st) {
if (u + n - st + 1 < m) return; // 剪枝
if (u == m) {
for (int x : chosen) System.out.print(x + " ");
System.out.print("\n");
return;
}
for (int x = st; x <= n; ++x) {
chosen[u] = x;
dfs(u + 1, x + 1);
}
}
// usage: dfs(0, 1)
int[] chosen = new int[m];
// 尝试把st...n放在chosen[u]
void dfs(int u, int st) {
if (u + n - st + 1 < m) return; // 剪枝
if (u == m) {
for (int x : chosen) System.out.print(x + " ");
System.out.print("\n");
return;
}
for (int x = st; x <= n; ++x) {
chosen[u] = x;
dfs(u + 1, x + 1);
}
}
// usage: dfs(0, 1)
C++
int chosen[M], u;
// 尝试把st...n放在chosen[u]
void dfs(int u, int st) {
if (u + n - st + 1 < m) return; // 剪枝
if (u == m) {
for (int i = 0; i < m; ++i) printf("%d ", chosen[i]);
putchar('\n');
return;
}
for (int x = st; x <= n; ++x) {
chosen[u] = x;
dfs(u + 1, x + 1);
}
}
// usage: dfs(0, 1)
int chosen[M], u;
// 尝试把st...n放在chosen[u]
void dfs(int u, int st) {
if (u + n - st + 1 < m) return; // 剪枝
if (u == m) {
for (int i = 0; i < m; ++i) printf("%d ", chosen[i]);
putchar('\n');
return;
}
for (int x = st; x <= n; ++x) {
chosen[u] = x;
dfs(u + 1, x + 1);
}
}
// usage: dfs(0, 1)
排列型枚举
把
Java
int[] chosen = new int[n];
boolean[] used = new boolean[n + 1];
// 尝试把1...n中没用过的数放在chosen[u]
void dfs(int u) {
if (u == n) {
for (int x : chosen) System.out.print(x + " ");
System.out.print("\n");
return;
}
for (int x = 1; x <= n; ++x) {
if (!used[x]) {
chosen[u] = x;
used[x] = true;
dfs(u + 1);
used[x] = false;
}
}
}
// usage: dfs(0)
int[] chosen = new int[n];
boolean[] used = new boolean[n + 1];
// 尝试把1...n中没用过的数放在chosen[u]
void dfs(int u) {
if (u == n) {
for (int x : chosen) System.out.print(x + " ");
System.out.print("\n");
return;
}
for (int x = 1; x <= n; ++x) {
if (!used[x]) {
chosen[u] = x;
used[x] = true;
dfs(u + 1);
used[x] = false;
}
}
}
// usage: dfs(0)
C++
int chosen[N];
bool used[N];
// 尝试把1...n中没用过的数放在chosen[u]
void dfs(int u) {
if (u == n) {
for (int i = 0; i < n; ++i) printf("%d ", chosen[i]);
putchar('\n');
return;
}
for (int x = 1; x <= n; ++x) {
if (!used[x]) {
chosen[u] = x;
used[x] = true;
dfs(u + 1);
used[x] = false;
}
}
}
// usage: dfs(0)
int chosen[N];
bool used[N];
// 尝试把1...n中没用过的数放在chosen[u]
void dfs(int u) {
if (u == n) {
for (int i = 0; i < n; ++i) printf("%d ", chosen[i]);
putchar('\n');
return;
}
for (int x = 1; x <= n; ++x) {
if (!used[x]) {
chosen[u] = x;
used[x] = true;
dfs(u + 1);
used[x] = false;
}
}
}
// usage: dfs(0)
剪枝
- 优化搜索顺序。
- 大部分情况下,我们应该优先搜索分支较少的节点。
- 排除等效冗余。
- 可行性剪枝。
- 最优性剪枝。
- 记忆化搜索(DP)。