0岛屿个数 - 蓝桥云课
问题描述
小蓝得到了一副大小为 M×N 的格子地图,可以将其视作一个只包含字符 '0'(代表海水)和 '1'(代表陆地)的二维数组,地图之外可以视作全部是海水,每个岛屿由在上/下/左/右四个方向上相邻的 '1' 相连接而形成。
在岛屿 A 所占据的格子中,如果可以从中选出 k 个不同的格子,使得他们的坐标能够组成一个这样的排列:
(x0,y0),(x1,y1),…,(xk−1,yk−1),其中 (xi+1modk,yi+1modk) 是由 (xi,yi) 通过上/下/左/右移动一次得到的(0≤i<k−1),此时这 k 个格子就构成了一个“环”。如果另一个岛屿 B 所占据的格子全部位于这个“环”内部,此时我们将岛屿 B 视作是岛屿 A 的子岛屿。若 B 是 A 的子岛屿,C 又是 B 的子岛屿,那 C 也是 A 的子岛屿。
请问这个地图上共有多少个岛屿?在进行统计时不需要统计子岛屿的数目。
输入格式
第一行一个整数 T,表示有 T 组测试数据。
接下来输入 T 组数据。对于每组数据,第一行包含两个用空格分隔的整数 M、N 表示地图大小;接下来输入 M 行,每行包含 N 个字符,字符只可能是 '0' 或 '1'。
输出格式
对于每组数据,输出一行,包含一个整数表示答案。
样例输入
2
5 5
01111
11001
10101
10001
11111
5 6
111111
100001
010101
100001
111111
样例输出
1
3
样例说明
对于第一组数据,包含两个岛屿,下面用不同的数字进行了区分:
01111
11001
10201
10001
11111
岛屿2在岛屿1的“环”内部,所以岛屿2是岛屿1的子岛屿,答案为1。
对于第二组数据,包含三个岛屿,下面用不同的数字进行了区分:
111111
100001
020301
100001
111111
注意岛屿3并不是岛屿1或者岛屿2的子岛屿,因为岛屿1和岛屿2中均没有“环”。
评测用例规模与约定
对于30的评测用例,1 ≤ M, N ≤ 10。
对于100的评测用例,1 ≤ T ≤ 10,1 ≤ M, N ≤ 50。
思路:
因为题目要求求得是岛屿的数量,如果一个环的岛屿,里面的岛屿不算岛屿。如果不是一个环,那么里面的岛屿仍然算一个岛屿。
1.
所以,我们可以先确定外海范围,通过8个方向的搜索,标记外海能到达的所有地方。bfs
2.
然后,标记所有陆地数量,同时用一个bool变量跟踪任何一个陆地是否能接触到外海。如果可以接触到外海,说明这个这个陆地(构成的岛屿)不是在环内的岛屿。dfs
代码如下:
#include<bits/stdc++.h>
using namespace std;
int dx[] = {-1,0,1,0};
int dy[] = {0,1,0,-1};
int dxe[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dye[] = {0, 1, 1, 1, 0, -1, -1, -1};
char a[55][55];
bool vis[55][55];
int n,m,ans = 0;
int T;
bool found = false;
struct Node{
int x,y;
};
bool check(int x,int y)//检查周围是否为外海
{
for(int i = 0 ; i < 4 ; i++)
{
int tx = x + dx[i];
int ty = y + dy[i];
if(tx >= 0 && tx <= n+1 && ty >= 0 && ty <= m + 1 && a[tx][ty] == '*')
return true;
}
return false;
}
void dfs(int x,int y)
{
vis[x][y] = true;//标记为岛屿
if(!found && check(x,y))
{
found = true;
}
for(int i = 0 ; i < 4 ; i++)
{
int tx = x + dx[i];
int ty = y + dy[i];
if(tx >= 1 && tx <= n && ty >= 1 && ty <= m&& !vis[tx][ty] && a[tx][ty] == '1')
{
dfs(tx,ty);
}
}
}
void bfs(int x,int y)
{
queue <Node> p;
p.push({x,y});
a[x][y] = '*';
while(!p.empty())
{
auto temp = p.front();
p.pop();
int x = temp.x;
int y = temp.y;
for(int i = 0 ; i < 8 ; i++)//外海斜着也会被渗入,所以需要八个方向
{
int tx = x + dxe[i];
int ty = y + dye[i];
if(tx >= 0 && tx <= n+1 && ty >= 0 && ty <= m + 1 && a[tx][ty] == '0')
{
a[tx][ty] = '*';//设置为外海
p.push({tx,ty});
}
}
}
}
int main(void)
{
cin >> T;
while(T--)
{
ans = 0;
memset(vis,false,sizeof(vis));//每组数据重置vis数组
cin >> n >> m;
for(int i = 0 ; i <= n + 1 ; i++)//扩大一个格子,方面搜索外海
{
for(int j = 0 ; j <= m + 1 ; j++)
{
a[i][j] = '0';
}
}
for(int i = 1 ; i <= n ; i++)//输入矩阵
{
for(int j = 1 ; j <= m ; j++)
{
cin >> a[i][j];
}
}
bfs(0,0);//标记外海
for(int i = 1 ; i <= n ; i++)//检查每一个岛屿
{
for(int j = 1 ; j <= m ; j++)
{
if(a[i][j] == '1' && !vis[i][j])
{
found = false;
dfs(i,j);
if(found)
ans++;
}
}
}
cout << ans << '\n';
}
return 0;
}