Algorithm8.2 DFS
[TOC]
dfs
向深递归
- 传参的确定 => 可以利用好递归调用栈机制
- 状态的判断 => 递归到每一层之后,所有参数共同组合决定出一个状态,这个状态维护是否重复
[数组一维模版 & 分层] 全排列
https://www.luogu.com.cn/problem/P1706
#include <iostream>
using namespace std;
int n, a[12], vis[12];
void dfs(int l) {
if (l == n) {
for (int i = 0; i < n; ++i) printf("%5d", a[i]);
printf("\n");
return;
}
for (int i = 1; i <= n; ++i) {
if (!vis[i]) {
a[l] = i;vis[i] = 1;
dfs(l+1);
vis[i] = 0;
}
}
}
int main() {
scanf("%d", &n);
dfs(0);
return 0;
}
素数环 & 分层
https://www.luogu.com.cn/problem/UVA524
1、注意是个环结构,所以说起点固定住就行,别的都是重复的
#include <iostream>
using namespace std;
int n, idx, a[18], vis[18];
#include <cmath>
bool isprime(int x) {
// printf("--- %d\n", x);
for (int i = 2; i <= sqrt(x); i++) if (x % i == 0) return false;
return true;
}
void dfs(int l) {
if (l == n) {
for (int i = 0; i < n-1; ++i) printf("%d ", a[i]);
printf("%d\n", a[n-1]);
return;
}
for (int i = 1; i <= n; ++i) {
if (!vis[i])
if (l == n - 1) {
if (isprime(a[0] + i) && isprime(a[l - 1] + i)) {
a[l] = i;
vis[i] = 1;
dfs(l + 1);
vis[i] = 0;
}
} else {
if (isprime(a[l - 1] + i)) {
a[l] = i;
vis[i] = 1;
dfs(l + 1);
vis[i] = 0;
}
}
}
}
int main() {
while (~scanf("%d", &n)) {
if(idx)printf("\n");
printf("Case %d:\n", ++idx);
a[0] = 1; vis[1] = 1;
dfs(1);
}
return 0;
}
[图上二维模版 & 特定终点] 深搜不同路径的个数
迷宫-可到达的路径总数:https://www.luogu.com.cn/problem/P1605
题目大意:有障碍,每条路径不能走回头路。问最多有多少条不同的路径可以到达终点。
#include <iostream>
using namespace std;
#define maxn 7
int mp[maxn][maxn], n, m, t, bx, by, ex, ey, tx, ty, dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, vis[maxn][maxn], ans = 0;
bool check(int x, int y){
if (x > 0 && x <= n && y > 0 && y <= m && !vis[x][y] && !mp[x][y]) return true;
return false;
}
void dfs(int x, int y){
if (x == ex && y == ey) {ans++;return;}
for (int i = 0; i < 4; ++i) {
int nx = x+dir[i][0], ny = y+dir[i][1];
if (check(nx, ny)) {
vis[nx][ny] = 1;
dfs(nx, ny);
vis[nx][ny] = 0;
}
}
}
int main() {
scanf("%d%d%d%d%d%d%d", &n, &m, &t, &bx, &by, &ex, &ey);
for (int i = 0; i < t; ++i) {
scanf("%d%d", &tx, &ty);
mp[tx][ty] = 1;
}
vis[bx][by] = 1;
dfs(bx, by);
printf("%d\n", ans);
return 0;
}
图上规则移动
https://www.luogu.com.cn/problem/P1784
1、在图上从左到右走到头,再走下一行的从左到右,知道走到最后的右下角(8,8)
#include <iostream>
using namespace std;
#define maxn 15
int a[maxn][maxn], block[maxn][maxn], col[maxn][maxn], row[maxn][maxn];
int getblock(int x, int y) {
if (x >= 0 && x <= 2) {
if (y >= 0 && y <= 2) return 0;
if (y >= 3 && y <= 5) return 1;
if (y >= 6 && y <= 8) return 2;
} else if (x >= 3 && x <= 5) {
if (y >= 0 && y <= 2) return 3;
if (y >= 3 && y <= 5) return 4;
if (y >= 6 && y <= 8) return 5;
} else {
if (y >= 0 && y <= 2) return 6;
if (y >= 3 && y <= 5) return 7;
if (y >= 6 && y <= 8) return 8;
}
}
void pr(){
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
printf("%d ", a[i][j]);
}
printf("\n");
}
exit(0);
}
void dfs(int x, int y) {
if (a[x][y])
if (x == 8 && y == 8) pr();
else if (y == 8) dfs(x+1, 0);
else dfs(x, y+1);
else
for (int j = 1; j <= 9; ++j) {
if (!block[getblock(x, y)][j] && !col[y][j] && !row[x][j]) {
block[getblock(x, y)][j] = 1;col[y][j] = 1;row[x][j] = 1;
a[x][y] = j;
if (x == 8 && y == 8) pr();
else if (y == 8) dfs(x+1, 0);
else dfs(x, y+1);
block[getblock(x, y)][j] = 0;col[y][j] = 0;row[x][j] = 0;
a[x][y] = 0;
}
}
}
int main() {
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
scanf("%d", &a[i][j]);
block[getblock(i, j)][a[i][j]] = 1;
col[j][a[i][j]] = 1;
row[i][a[i][j]] = 1;
}
}
dfs(0, 0);
return 0;
}
图上 [模版] 联通块数
https://www.luogu.com.cn/problem/P1596
dfs实现 // 用bfs也可以实现,只是不同的搜索策略。
参数:二维坐标系中的横纵坐标x和y
状态:对于横纵坐标中每个点是否都有去到过,用一个
vis[][]
来维护
#include <iostream>
using namespace std;
#define maxn 105
int n, m, cnt, dir[8][2] = {{1, 0}, {-1, 0}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}, {0, 1}, {0, -1}};
char a[maxn][maxn];
void dfs(int x, int y) {
for (int i = 0; i < 8; ++i) {
int nx = x + dir[i][0], ny = y+dir[i][1];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && a[nx][ny] == 'W') {a[nx][ny] = '.';dfs(nx, ny);}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i) scanf("%s", a[i]);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
if (a[i][j] == 'W') {cnt++;a[i][j] = '.';dfs(i, j); }
printf("%d\n", cnt);
return 0;
}