2018第九届蓝桥杯之全球变暖 (BFS)

第九题 全球变暖

【问题描述】
你有一张某海域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;
	
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值