P8662 [蓝桥杯 2018 省 AB] 全球变暖

P8662 蓝桥杯 2018 省 AB 全球变暖

题目描述

你有一张某海域 N×NN \times NN×N 像素的照片,. 表示海洋、 # 表示陆地,如下所示:

复制代码
.......
.##....
.##....
....##.
..####.
...###.
.......

其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 222 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:

复制代码
.......
.......
.......
.......
....#..
.......
.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入格式

第一行包含一个整数 NNN。(1≤N≤1000)(1 \le N \le 1000)(1≤N≤1000)。

以下 NNN 行 NNN 列代表一张海域照片。

照片保证第 111 行、第 111 列、第 NNN 行、第 NNN 列的像素都是海洋。

输出格式

一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
7 
.......
.##....
.##....
....##.
..####.
...###.
.......  

输出 #1

复制代码
1

说明/提示

时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛

题目解析

这道题目很有意思,一般遇到类似洪水填充题目,会对连通块进行填充,然后记录连通块的个数,但是这道题目可能会出现一个岛屿经过淹没后变成两个连通块的情况,这种情况,绝大部分人一开始都想不到。

比如

C++ 复制代码
..........
.##.......
.##.......
....##.##.
..#######.
...###.##.
..........

经过淹没后是

C++ 复制代码
..........
..........
..........
..........
....##.#..
..........
..........

我们发现第二个岛屿,从1个岛屿变成了两个连通块。淹没前是两个岛屿,淹没后经过洪水填充,还是两个岛屿,但事实上消失了一个岛屿。所以这种情况需要特殊处理。

代码实现 36pts 没有考虑一个岛屿变成两个连通块的代码

C++ 复制代码
//这里使用了两次洪水填充
#include<bits/stdc++.h>
using namespace std;
long long n,nx,ny,dx[4]={0,-1,0,1},dy[4]={1,0,-1,0},s=0,s1=0;
char a[1010][1010],b[1010][1010];
void bfs(int x,int y,char a[][1010]){
	queue<pair<int,int>> q;
	q.push({x,y});
	pair<int ,int > p;
	while(!q.empty()){
		p=q.front();
		q.pop();
		for(int i=0;i<=3;i++){
			nx=p.first+dx[i];
			ny=p.second+dy[i];
			if(nx<1||nx>n||ny<1||ny>n)continue;
			if(a[nx][ny]!='#')continue;
			a[nx][ny]='.';
			q.push({nx,ny});
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			b[i][j]=a[i][j];
		}	
	}
	//淹没后的新矩阵b
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]=='#'&&(a[i][j-1]=='.'||a[i-1][j]=='.'||a[i][j+1]=='.'||a[i+1][j]=='.')){
				b[i][j]='.';
			}
		}
	}
	//广度优先搜索,洪水填充a,得到淹没前的连通块个数
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]=='#'){
				bfs(i,j,a);
				s++;
			}
		}
	}	
	
	
	//广度优先搜索,洪水填充b,得到淹没后的连通块个数
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(b[i][j]=='#'){
				bfs(i,j,b);
				s1++;
			}
		}
	}
	cout<<s-s1;//淹没前-淹没后
	return 0;
}

代码实现 100pts

C++ 复制代码
#include<bits/stdc++.h>
using namespace std;
long long n,nx,ny,dx[4]={0,-1,0,1},dy[4]={1,0,-1,0},s=0,s1=0;
char a[1010][1010],b[1010][1010];
long long a1[1010][1010];
map<int ,int > mp;//淹没后的岛屿个数
void bfs(int x,int y){
	queue<pair<int,int>> q;
	q.push({x,y});
	a1[x][y]=s;
	pair<int ,int > p;
	while(!q.empty()){
		p=q.front();
		q.pop();
		for(int i=0;i<=3;i++){
			nx=p.first+dx[i];
			ny=p.second+dy[i];
			if(nx<1||nx>n||ny<1||ny>n)continue;
			if(a[nx][ny]!='#')continue;
			a[nx][ny]='.';
			a1[nx][ny]=s;//对不同的岛屿标记不一样的数字  
			q.push({nx,ny});
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			b[i][j]=a[i][j];
		}	
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]=='#'&&(a[i][j-1]=='.'||a[i-1][j]=='.'||a[i][j+1]=='.'||a[i+1][j]=='.')){
				b[i][j]='.';
			}
		}
	}
	//广度优先搜索,洪水填充
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]=='#'){
				s++;
				bfs(i,j);
				
			}
		}
	}	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(b[i][j]=='#'){
				mp[a1[i][j]]=1;//对出现的岛屿做标记
			}
		}
	}
	cout<<s-mp.size();//mp的size就是淹没后的岛屿个数
	return 0;
}
相关推荐
辰烨chenye1 小时前
LeetCode Hot 100 题解 · 普通数组篇
算法·leetcode·职场和发展
hqyjzsb4 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye4 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术4 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
sanjiaomao3335 小时前
从论文公式到Python实现:用单元测试校验滑动平均算法
python·算法·单元测试
Keven_115 小时前
算法札记:ACM适用的很骚的C++语法(持续更新)
开发语言·c++
乐迪信息5 小时前
如何通过AI防爆摄像机精准判断船舶超速?
大数据·人工智能·算法·安全·目标跟踪
mengzhi啊5 小时前
QPluginLoader 动态 DLL 插件版,支持插件之间通信,广播。请求和应答
c++·qt
大圣编蚕6 小时前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
小玮看世界7 小时前
[Python]OD算法在OD实际运用转化参考清单
开发语言·python·算法