全球变暖详细题解(蓝桥杯bfs)
题目描述全球变暖你有一张某海域 N×N 像素的照片,”.”表示海洋、”#”表示陆地,如下所示:….##….##……##.…####.…###.…其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2 座岛屿。由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。例如
题目描述
全球变暖
你有一张某海域 N×N 像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
…
.##…
.##…
…##.
…####.
…###.
…
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。
具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…
…
…
…
…#…
…
…
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数N。
以下 N 行 N 列,包含一个由字符”#”和”.”构成的 N×N 字符矩阵,代表一张海域照片,”#”表示陆地,”.”表示海洋。
照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。
输出格式
一个整数表示答案。
数据范围
1≤N≤1000
输入样例1:
7
…
.##…
.##…
…##.
…####.
…###.
…
输出样例1:
1
输入样例2:
9
…
.##.##…
.#####…
.##.##…
…
.##.#…
.#.###…
.#…#…
…
输出样例2:
1
————————————————
蓝桥杯全球变暖题目链接https://www.lanqiao.cn/problems/178/learning/
【解题思路】
相信这道题大家一看都能明白需要检测连通性,检测连通性dfs和bfs都可,我这里用了bfs方法更方便。可是,即使我们知道如何判断连通在一起的陆地也不好找到岛屿的淹没条件。
错误思路(未想到可以不用看)
淹没前检测一遍连通性,判断有多少岛屿。通过淹没条件独立淹没一遍(即遍历每一个‘#’判断并且替换成‘.’),这样得到淹没后的海图再检测一遍连通性,两者相减。①首先这样的做法比较冗长。②而且刚开始我采用dfs出口统计岛屿数目,即使我能将每一个岛屿标记出来,由于岛屿的二维性导致dfs可能有多个出口,使得岛屿数不准确。③还有一个大问题,岛屿是由多块陆地组成,单独一块陆地可成不了岛屿,这样还得单独判断每次检测连通时有多少块陆地,极其繁琐。④最后还有一个巨大漏洞,即是未被完全淹没的岛屿最后剩下的可能是岛屿,也有可能只是一块陆地。这样又增加了判断条件。
年前那晚的惨痛遭遇让我记忆犹新,经历了三小时左右的编码和反复调测后,代码累计到140来行终于把我写崩溃。
缓到年后我才重新构思这道题,改用更加方便的bfs检测连通性,并且在大思路上做了巨大调整。这里和我一起崩的还有和我一起刷题的一个小伙伴哈哈哈,接下来讲一讲正确思路
【正确思路】
显然,做蓝桥杯的算法题不能太单纯地使用顺序逻辑的方法。得找一个四两拨千斤的巧妙利用连通性的逻辑。
之前我忽略了最为直接的一个判断岛屿是否淹没的条件,即是若一个陆地上下左右都是陆地,那么该陆地一定不会被淹没!并且,该陆地一定是岛屿的组成部分!
想到这个判断条件这道题难度直线下降,只要判断每一块陆地是否会被淹没就能知道陆地所在岛屿是否被淹没。并且,我们只需要把与这块陆地所在的岛屿全部标记,避免重复判断就可以了,这里使用bfs标记。
每bfs一次,即是标记了一座岛屿,并且判断了该岛屿是否会被完全淹没。
【代码献上】
#include<bits/stdc++.h>
using namespace std;
char a[1001][1001];//保存原来的陆地和海洋
int vis[1001][1001];//标记跟踪数组
int ans=0;//记录不会被淹没的岛屿数
int flag=0;//不会被淹没标志,如果为1表示不会被淹没
int n;//输入参数n,置于全局方便函数内使用
struct land{//用结构体方便保存陆地坐标
int x;
int y;
land(int a,int b){
x=a;
y=b;
}
};
int bfs(int i,int j){//bfs算法,用于检测连通的陆地块,并且判断不会被淹没的岛屿数目
vis[i][j]=1;
queue <land> q;
land lan(i,j);
q.push(lan);
while(q.size()){
land lan2=q.front();//cout<<q.front().x<<" "<<q.front().y<<endl;打印测试是否死循环
q.pop();
int x=lan2.x,y=lan2.y;
int x1=lan2.x-1,x2=lan2.x+1,y1=lan2.y-1,y2=lan2.y+1;
if(x1>=2&&x2<=n-1&&y1>=2&&y2<=n-1&&a[x1][y]=='#'&&a[x2][y]=='#'&&a[x][y1]=='#'&&a[x][y2]=='#'){
//如果该陆地上下左右都是陆地则表明该陆地所在岛屿不会被淹没
flag=1;
}
//若flag=1我们还是继续把整块岛屿标记完,避免重复统计未淹没岛屿
if(x1>=2&&a[x1][y]=='#'&&vis[x1][y]==0){
//向上
vis[x1][y]=1;
land lan3(x1,y);
q.push(lan3);
}
if(x2<=n-1&&a[x2][y]=='#'&&vis[x2][y]==0){
//向下
vis[x2][y]=1;
land lan4(x2,y);
q.push(lan4);
}
if(y1>=2&&a[x][y1]=='#'&&vis[x][y1]==0){
//向左
vis[x][y1]=1;
land lan5(x,y1);
q.push(lan5);
}
if(y2<=n-1&&a[x][y2]=='#'&&vis[x][y2]==0){
//向右
vis[x][y2]=1;
land lan6(x,y2);
q.push(lan6);
}
}
return 0;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
for(int i=2;i<=n-1;i++)
for(int j=2;j<=n-1;j++)
{
if(a[i][j]=='#'&&vis[i][j]==0)
{
flag=0;
bfs(i,j);
if(flag==0) ans++;//改变flag参数后统计淹没岛屿,之前是统计的未淹没岛屿
}
}
cout<<ans<<endl;
return 0;
}
最后感言
代码各有不同,只是编码能力的体现。做蓝桥杯这种题得想到巧解思路最为关键。谢谢观看~
更多推荐
所有评论(0)