AcWing 1113. 红与黑(传送门)
思路分析:
这个题可以用 bfs 宽度优先搜索
或者 dfs 深度优先搜索
-
bfs
- 优点:
- 可求最短距离(第一次搜到的点,一定是最短的)
- 更好理解,比较符合人的思维方式
- 缺点:
- 需要自己手动写队列
- 优点:
-
dfs
- 优点:
- 更方便
- 代码较短
- 缺点:
- 在某些OJ上存在暴栈的可能
- 思维更像计算机思维,不好理解
- 优点:
那么下面就先说一下 bfs 宽搜 也就是 Flood Fill算法 中文名:洪水灌溉
时间复杂度 O(mn) ,m和n分别为矩阵的长宽
bfs 事实上是一个点一个点的前进,就先遍历当前所在点的上右下左四个方向,然后将可以走的点存入队列中,并从队列中删除当前点,然后对队列中的所有点进行相同的操作,直到队列中没有符合要求点。
AC代码:
#include <iostream>
#include <cstdio>
#include <queue>
#define x first
#define y second
#define ll long long
using namespace std;
typedef pair<int,int> PII; // 坐标存法
const int N = 25;
char a[N][N];
// 顺序:上右下左
int dx[] = {
-1,0,1,0};
int dy[] = {
0,1,0,-1};
int w,h;
int bfs(int sx,int sy) {
queue<PII> q; // 队列中存坐标
q.push({
sx,sy});
a[sx][sy] = '#'; // 标记一下初始位置
int res = 0; // 最终结果,表示能搜到点的数量,也就是最后的答案
while(q.size()) {
auto t = q.front();
q.pop();
res++; // 每次从队列中取出一个点,结果 +1
for(int i = 0;i < 4; i++) {
int x = t.x + dx[i];
int y = t.y + dy[i];
// 遍历上右下左 4个位置,当该位置出界,或者已经被走过
if( x < 0 || x >= h || y < 0 || y >= w || a[x][y] != '.')
continue;
// 如果可以扩展的话,首先先标记一下
a[x][y] = '#';
// 然后把当前坐标存在队列中
q.push({
x,y});
}
}
return res;
}
int main() {
int x,y;
while(~scanf("%d%d",&w,&h)) {
if( w == 0 && h == 0)
break;
for(int i = 0;i<h;i++)
cin >> a[i];
for(int i = 0;i<h;i++)
for(int j = 0; j < w; j++)
if(a[i][j] == '@') {
x = i;
y = j;
}
cout << bfs(x,y) << endl;
}
return 0;
}
再来说下 dfs 深搜
dfs 事实上描述的是一个不断递归和回溯的过程,先从一个有效的方向出发,按照上右下左顺序,一直进行下去,直到没有有效方向,然后往前回溯,直到所有已经走过的点的有效方向全部失效,最后得出答案。
AC代码:
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N = 25;
char a[N][N];
// 顺序:上右下左
int dx[] = {
-1, 0, 1, 0};
int dy[] = {
0, 1, 0, -1};
int w, h;
int dfs(int x, int y) {
int res = 1;
// 首先将起始点进行标记
a[x][y] = '#';
// 枚举上右下左四个临格
for (int i = 0; i < 4; i++) {
// 写出新格坐标
int new_x = x + dx[i];
int new_y = y + dy[i];
// 如果在界内,且可以走的话,累加结果,并且递归新的dfs
if( new_x >= 0 && new_x < h && new_y >= 0 && new_y < w && a[new_x][new_y] == '.')
res += dfs(new_x,new_y);
}
return res;
}
int main() {
int x, y;
while (~scanf("%d%d", &w, &h)) {
if (w == 0 && h == 0)
break;
for (int i = 0; i < h; i++)
cin >> a[i];
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if (a[i][j] == '@') {
x = i;
y = j;
}
cout << dfs(x, y) << endl;
}
return 0;
}