题目
问题描述
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
…
.##…
.##…
…##.
…####.
…###.
…
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…
…
…
…
…#…
…
…
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
输出格式
一个整数表示答案。
样例输入
7
…
.##…
.##…
…##.
…####.
…###.
…
样例输出
1
分析
一个#和所有与它相连的#组成一块岛屿,这里的相连指的是上下左右,那我们可以先计算出来变化前的岛屿数量,然后模拟变化被淹没的岛屿,然后在计算变化后的岛屿数量,然后相减即是答案,计算岛屿的数量需要用到dfs标记一个岛屿的所有陆地,变化就需要模拟+判断即可
代码部分
1.循环遍历
遍历整个地图,如果出现#就计数加一,然后dfs标记和它相连的所有#
cin>>n;
vector<vector<char> > _map(n,vector<char>(n)); //地图
vector<vector<bool> > vis(n,vector<bool>(n,0)); //标记
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>_map[i][j];
int oldcnt=0;
for(int i=0;i<n;i++) //计算变化前岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis[i][j]==0)
{
oldcnt++;
dfs(i,j,_map,vis);
}
}
}
2.dfs
我们首先要清楚dfs做的事情,从当前位置出发标记所有相连的#,分别是上下左右四个方向,所以为了简便我们开两个一维的数组作为方向坐标代表方向的变化,然后就是遍历四个方向,加判断下一个位置是否能走是否合法,每次标记当前的位置为已经走过
const int dx[4]={
0,0,1,-1}; //方向
const int dy[4]={
1,-1,0,0};
void dfs(int x,int y,vector<vector<char> > &_map,vector<vector<bool> > &vis)
{
//出口
vis[x][y]=1;
//现在能做的事情
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n&&
vis[x+dx[i]][y+dy[i]]==0&&
(_map[x+dx[i]][y+dy[i]]=='#'||_map[x+dx[i]][y+dy[i]]=='!'))
{
dfs(x+dx[i],y+dy[i],_map,vis);
}
}
}
3.模拟判断整个地图
之前我是模拟判断当前位置如果会被淹没我就把它改变成.,后来发现这样是不行的,最后地图中所有的格子都会被变成.,然后我将要淹没的格子改变成了!
bool check(int x,int y,vector<vector<char> > &_map) //判断该岛屿是否会被淹没
{
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n)
{
if(_map[x+dx[i]][y+dy[i]]=='.')
return true;
}
}
return false;
}
for(int i=0;i<n;i++) //改变地图标记被淹没的陆地
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&check(i,j,_map))
{
_map[i][j]='!';
}
}
}
4.判断变化后的岛屿数量
如果我们直接像之前那样计算岛屿数量是不行的,因为有的岛屿变化后,如果直接计算会变成两个岛屿,这里题中给定的含义不是很清楚,所以我们判断的时候从#出发,但是!的地方也要进行标记和判断,因为这些陆地之前都是属于一个岛屿
vector<vector<bool> > vis2(n,vector<bool>(n,0)); //标记
int nowcnt=0;
for(int i=0;i<n;i++) //计算变化后岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis2[i][j]==0)
{
nowcnt++;
dfs(i,j,_map,vis2);
}
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
int n;
const int dx[4]={
0,0,1,-1}; //方向
const int dy[4]={
1,-1,0,0};
void dfs(int x,int y,vector<vector<char> > &_map,vector<vector<bool> > &vis)
{
//出口
vis[x][y]=1;
//现在能做的事情
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n&&
vis[x+dx[i]][y+dy[i]]==0&&
(_map[x+dx[i]][y+dy[i]]=='#'||_map[x+dx[i]][y+dy[i]]=='!'))
{
dfs(x+dx[i],y+dy[i],_map,vis);
}
}
}
bool check(int x,int y,vector<vector<char> > &_map) //判断该岛屿是否会被淹没
{
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n)
{
if(_map[x+dx[i]][y+dy[i]]=='.')
return true;
}
}
return false;
}
int main (void)
{
cin>>n;
vector<vector<char> > _map(n,vector<char>(n)); //地图
vector<vector<bool> > vis(n,vector<bool>(n,0)); //标记
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>_map[i][j];
int oldcnt=0;
for(int i=0;i<n;i++) //计算变化前岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis[i][j]==0)
{
oldcnt++;
dfs(i,j,_map,vis);
}
}
}
for(int i=0;i<n;i++) //改变地图标记被淹没的陆地
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&check(i,j,_map))
{
_map[i][j]='!';
}
}
}
/*
for(int i=0;i<n;i++) //输出改变后的地图
{
for(int j=0;j<n;j++)
{
cout<<_map[i][j];
}
cout<<endl;
}
*/
vector<vector<bool> > vis2(n,vector<bool>(n,0)); //标记
int nowcnt=0;
for(int i=0;i<n;i++) //计算变化后岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis2[i][j]==0)
{
nowcnt++;
dfs(i,j,_map,vis2);
}
}
}
cout<<oldcnt-nowcnt;
return 0;
}
总结
虽然这道题代码量很多,但是有很多地方都是重复的,思想也并不难,只是基础的dfs,但是有一些细节还是需要注意的