一、题目链接
二、题目分析
(一)算法标签
FloodFill BFS DFS
(二)解题思路
第一步:计算出有多少个连通块(岛屿)
一般而言,找连通块的方法有两种,第一种是遍历(包括DFS 和BFS),第二种是并查集。
这里以bfs为例,具体如下:
遍历每一个点,如果没有被访问过并且是#的话,那么bfs搜索一下,同时cnt++
第二步:计算出有多少个会被完全淹没,这里与上一步同时求了
详细了解搜索类题目(DFS、BFS),请移步DFS BFS 搜索题目归纳
三、AC代码
解法一(BFS):
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 1010;
char g[N][N];
bool st[N][N];
int n;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
// 判断周围是否都是岛屿#
bool check(int x, int y)
{
int cnt = 0;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '#')
cnt ++ ;
}
if (cnt == 4) return true;
else return false;
}
bool bfs(int x, int y)
{
st[x][y] = true;
queue<PII> q;
q.push({x, y});
int cnt = 0;
while (!q.empty())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i ++ )
{
int a = t.x + dx[i], b = t.y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '.') continue;
if (!st[a][b] && check(a, b)) cnt ++ ;
if (!st[a][b] && g[a][b] == '#')
{
st[a][b] = true;
q.push({a, b});
}
}
}
if (cnt) return false;
else return true;
}
int main()
{
cin >> n;
for (int i = 0; i < n ; i ++ ) scanf("%s", g[i]);
int res = 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)) res ++ ;
}
}
cout << res << endl;
return 0;
}
解法二(DFS):
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 1010;
char g[N][N];
bool st[N][N], flag;
int n;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
// 判断周围是否都是岛屿#
bool check(int x, int y)
{
int cnt = 0;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '#')
cnt ++ ;
}
if (cnt == 4) return true;
else return false;
}
void dfs(int x, int y)
{
// cout << x << ' ' << y << endl;
st[x][y] = true;
if (check(x, y)) flag = true;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '.') continue;
// if (!st[a][b] && g[a][b] == '#' && check(a, b)) return false;
if (!st[a][b] && g[a][b] == '#')
{
dfs(a, b);
// st[a][b] = false;
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n ; i ++ ) scanf("%s", g[i]);
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
{
if (!st[i][j] && g[i][j] == '#')
{
flag = false;
dfs(i, j);
if (!flag) res ++ ;
}
}
cout << res << endl;
return 0;
}
下面给出dfs错误代码(只过了1个测试用例):
错误原因:dfs函数的开头check判断直接返回,可能导致该连通块还没搜完就返回了,导致下一次dfs还是在该连通块内
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 1010;
char g[N][N];
bool st[N][N];
int n;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
// 判断周围是否都是岛屿#
bool check(int x, int y)
{
int cnt = 0;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '#')
cnt ++ ;
}
if (cnt == 4) return true;
else return false;
}
bool dfs(int x, int y)
{
// cout << x << ' ' << y << endl;
st[x][y] = true;
if (check(x, y)) return false;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (g[a][b] == '.') continue;
// if (!st[a][b] && g[a][b] == '#' && check(a, b)) return false;
if (!st[a][b] && g[a][b] == '#')
{
return dfs(a, b);
// st[a][b] = false;
}
}
return true;
}
int main()
{
cin >> n;
for (int i = 0; i < n ; i ++ ) scanf("%s", g[i]);
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
{
if (!st[i][j] && g[i][j] == '#')
{
if (dfs(i, j)) res ++ ;
}
}
cout << res << endl;
return 0;
}