题解:P9243 [蓝桥杯 2023 省 B] 岛屿个数
题目要求求主岛屿个数,即求接触到最外层流入的海水的岛屿个数。直接判断一个岛屿是否是另一个岛屿的子岛屿不好判断,所以不如放弃掉子岛屿,而只关注主岛屿的个数,换句话说,只要接触到从最外层流入的海水的岛屿都一定是主岛屿。
不过,一个主岛屿如果不是通过严格的上下左右操作形成一个环,而是存在类似样例二的斜跨格子的情况,那么该主岛屿并不形成环,换句话说就是海水可以通过斜跨格子的方式流入。
将上述思路运用在代码中就会有以下要点:
- 海水流入的方向应当有上、下、左、右、左上、右上、左下、右下,八种方向进行操作。
- 判断岛屿是否是联通,必须严格按照上、下、左、右,四个方向进行连接。
- 与海水直接接触的岛屿必然是主岛屿。
理解以上要点后,思路就出来了。首先,在地图的最外圈遍历,如果遇到海水
需要注意的是,如果是从所给地图的最外圈进行遍历判断,则需要注意最外圈全部被主岛屿
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 55;
int t,n,m,res;
bool vis[N][N];
char mp[N][N];
int nextStep[8][2] = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
struct inner{
int x,y;
};
void bfs1(int x,int y){
queue<inner> que;
que.push({x,y});
res++;
while(!que.empty()){
auto tt = que.front();
que.pop();
for(int i=0;i<4;i++){
int tx = tt.x + nextStep[i][0];
int ty = tt.y + nextStep[i][1];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]=='1'&&!vis[tx][ty]){
que.push({tx,ty});
vis[tx][ty] = true;
}
}
}
}
void bfs0(int x,int y){
queue<inner> que;
que.push({x,y});
vis[x][y] = true;
while(!que.empty()){
auto tt = que.front();
que.pop();
for(int i=0;i<8;i++){
int tx = tt.x + nextStep[i][0];
int ty = tt.y + nextStep[i][1];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&!vis[tx][ty]){
vis[tx][ty] = true;
if(mp[tx][ty]=='1') bfs1(tx,ty);
else que.push({tx,ty});
}
}
}
}
void solve(){
bool flag = false;
res = 0;
cin >> n >> m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin >> mp[i][j];
vis[i][j] = false;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i==1 || i==n || j==1 || j==m)//对边缘的海水进行 bfs0
if(!vis[i][j] && mp[i][j] == '0'){
bfs0(i,j);
flag = true;
}
if(!flag) res = 1;//以防一个岛屿占满了外边界的情况
cout << res << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> t;
while(t--){
solve();
}
return 0;
}