你有一张某海域 NxNNxNNxN 像素的照片,".“表示海洋、”#"表示陆地,如下所示:
. . . . . . .
. # # . . . .
. # # . . . .
. . . . # # .
. . # # # # .
. . . # # # .
. . . . . . .
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . # . .
. . . . . . .
. . . . . . .
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
第一行包含一个整数 N (1≤N≤1000)N\ (1 \leq N \leq 1000)N (1≤N≤1000)。
以下 NNN 行 NNN 列代表一张海域照片。
照片保证第 1 行、第 1 列、第 NNN 行、第 NNN 列的像素都是海洋。
输出一个整数表示答案。
输入
7
…
.##…
.##…
…##.
…####.
…###.
…
输出
1
这道题主要考察的是对数组遍历的应用,可以采用深度优先搜索,也可以采用广度优先搜索,但是由于数据量比较大的原因在进行深度优先搜索时可能会使深度过深,所以我们采用广度优先搜索的方法遍历。
此外,我们采用坐标的方式访问每个陆地,用队列将上下左右的陆地加入队列并标记被访问,同时记录周围有水的陆地有多少,在一个连通块内如果陆地的的数目和周围有水的陆地的数目相等的话,则可以认为这个岛屿最终将会完全沉没。
具体代码如下:
#include <iostream>
#include <queue>
using namespace std;
int n,ans;//分别为规模,答案
//横纵坐标跨度,组合使用
int dx[]={0, 0, 1, -1};
int dy[]={1, -1, 0, 0};
char data[1000][1000];
int mark[1000][1000];
//自定义Point类型,存储一个格子的横纵坐标
struct Point{
int x,y;
};
void bfs(int i, int j){
mark[i][j]=1;//标记为已访问
queue<Point> q;//新建一个队列
q.push({i,j});//将当前格子封装到Point,插入队列
int cnt1=0,cnt2=0;//分别记录当前这个块的#数量以及和.相邻的#的数量
while(!q.empty()){
Point first = q.front();
q.pop();
cnt1++;//#数量
bool swed = false;//标记弹出的#四周是否有.
// 在四个方向上产生新的坐标
for(int k=0; k<4; ++k){
int x=first.x+dx[k];
int y=first.y+dy[k];
//如果四个方向上任意一个方向上有.,就将被淹没,采用布尔型变量
if(0<=x && x<n && 0<=y && y<n && data[x][y]=='.') swed=true;
// 周边的#如果未被访问,将其加入队列
if(0<=x && x<n && 0<=y && y<n && data[x][y]=='#' && mark[x][y]==0){
q.push({x,y});
mark[x][y]=1;
}
}
if(swed)
cnt2++;
}
// 一个连通块就被访问完了
//连通块内标记都变为1,#数量记录进cnt1,周边有.的#的数量被记录为cnt2
if(cnt1==cnt2) ans++;
}
int main()
{
// 请在此输入您的代码
scanf("%d",&n);
getchar();
for(int i=0; i<n;i++){
for(int j=0; j<n; j++){
scanf("%c",&data[i][j]);
}
getchar();
}
// 双循环检验#,从#开始广度优先搜索
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
if(mark[i][j]==0 && data[i][j]=='#'){
bfs(i,j);
}
}
}
printf("%d",ans);
return 0;
}
最后就可得出正确结果。