第九题 全球变暖
【问题描述】
你有一张某海域NxN像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
…….
.##….
.##….
….##.
…####.
…###.
…….
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…….
…….
…….
…….
….#…
…….
…….
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。
【输入样例】
7
…….
.##….
.##….
….##.
…####.
…###.
…….
【输出样例】
1
【输入样例】
10
…
.###…###.
.###…###.
.########.
…
.###…#…
.#.#…#…
.###…
…
…
【输出样例】
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
分析
典型的连通块问题,解决此类问题可以用dfs或bfs来求解,主要问题就是数据规模限制,本题中N=1000,最大为10^6个点,如果采用dfs可能会导致搜索深度过深,导致栈内存溢出,所以采用bfs算法解题
思路
创建陆地结构体,标记出坐标,然后采用队列存储陆地节点,进行一层一层遍历。分别记录当前这个连通块的#的数量以及和.相邻的#的数量,如果这两个值相等则该连通块对应的小岛会被淹没
参考代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#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];
//存储一个格子的横纵坐标
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++;//当前#+1
bool flag=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]=='.')
flag=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(flag)
cnt2++;
}
//一个连通块就被访问完了 连通块中#的数量记录在cnt1,周边有.的#数量记录在cnt2
if(cnt1==cnt2)
ans++;
}
int main()
{
cin>>N;
getchar();//吃回车
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
cin>>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);//进行宽搜遍历
}
}
cout<<ans<<endl;
}