欢迎点赞,指点 还有一个月 ✈蓝桥杯✈
Flood Fill (洪水填充) 求解 对于网格图的连通块 问题
提取:
g[ ][ ]字符矩阵的读取技巧
bool st[ ]的作用及应用
g[ ][ ]将走过的格子修改 从而省去 bool st[ ]
BFS 用 g[ ][ ]标记为 ' # ' 省去bool st[ ]的表示
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 25;
char g[N][N];
int n,m;
queue<PII> q;
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
int bfs(int sx,int sy)
{
g[sx][sy] = '#';
q.push({sx,sy});
int res = 1;
while(q.size())
{
auto t = q.front();
q.pop();
int a = t.first,b = t.second;
for(int i = 0;i < 4;i++)
{
int x = a + dx[i],y = b + dy[i];
if(x < 0 || x >= n || y < 0 || y >= m) continue;
if(g[x][y] == '#') continue;
g[x][y] = '#'; // 相当于 st[] 数组
q.push({x,y});
res++;
}
}
return res;
}
int main()
{
while(cin >> m >> n,n || m) // 注意 题目描述 n m 行列
{
for(int i = 0;i < n;i++) scanf("%s",g[i]);
PII start;
for(int i = 0;i < n;i++)
for(int j = 0;j < m;j++)
if(g[i][j] == '@') start = {i,j};
cout << bfs(start.first,start.second) << endl;
}
return 0;
}
DFS (flood fill) 理解过程
#include <bits/stdc++.h>
using namespace std;
const int N = 25;
int n,m;
char g[N][N];
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
int dfs(int a,int b)
{
int res = 1;
g[a][b] = '#';
for(int i = 0;i < 4;i++)
{
int x = a + dx[i],y = b + dy[i];
if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] != '#')
res += dfs(x,y); // 理解 不断向下递归与 回溯 的过程
} // 通过画网格图进行手动模拟 来理解
return res;
}
int main()
{
while(cin >> m >> n,n || m)
{
for(int i = 0;i < n;i++) scanf("%s",g[i]);
int a = 0,b = 0;
for(int i = 0;i < n;i++)
for(int j = 0;j < m;j++)
if(g[i][j] == '@') a = i,b = j;
cout << dfs(a,b) << endl;
}
return 0;
}
' # ' 变为 ' . ' 省去 bool st[ ]
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 1010;
int n,m;
char g[N][N];
bool st[N][N];
queue<PII> q;
void bfs(int sx,int sy)
{
g[sx][sy] = '.';
q.push({sx,sy});
while(q.size())
{
auto t = q.front();
q.pop();
int a = t.first,b = t.second;
for(int i = a - 1;i <= a + 1;i++) //对于 相邻8个方向的偏移
for(int j = b - 1;j <= b + 1;j++)
{
if(i < 0 || i >= n || j < 0 || j >= m) continue;
if(st[i][j] || g[i][j] == '.') continue;
g[i][j] = '.';
st[i][j] = true;
q.push({i,j});
}
}
}
int main()
{
cin >> n >> m;
for(int i = 0;i < n;i++) scanf("%s",g[i]); // 注:语法的细节 不用 &g[i] "%d" 用&g[i];
int res = 0;
for(int i = 0;i < n;i++) // 遍历每个字符 寻找并同时 标记连通块
for(int j = 0;j < m;j++)
if(g[i][j] == 'W')
{
bfs(i,j);
res++;
}
cout << res << endl;
return 0;
}
' w ' 变为 ' . ' st[ ]数组在 bfs( )中 用于判断是否重复遍历 然后入队
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 1010;
int n;
char g[N][N];
bool st[N][N];
queue<PII> q;
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
bool bfs(int sx,int sy)
{
int total = 0,bound = 0;
st[sx][sy] = true;
q.push({sx,sy});
total++;
while(q.size())
{
auto t = q.front();
q.pop();
int a = t.first,b = t.second;
int res = 0;
bool is_bound = false;
for(int i = 0;i < 4;i++)
{
int x = a + dx[i],y = b + dy[i];
if(x < 0 || x >= n || y < 0 || y >= n) continue;
if(st[x][y]) continue;
if(g[x][y] == '.')
{
is_bound = true; // 四周只要有水就会被淹没
continue;
}
st[x][y] = true;
q.push({x,y});
total++;
}
if(is_bound) bound++;
}
return total == bound;
}
int main()
{
cin >> n;
for(int i = 0;i < n;i++) scanf("%s",g[i]);
int ans = 0;
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
if(!st[i][j] && g[i][j] == '#')
if(bfs(i,j)) ans++;
cout << ans << endl;
return 0;
}
' # ' 不变为 ' . ' st[ ] 出现在for循环遍历中 且 出现在bfs( )中用于判断 然后入队