题目:
难点:
1. 读懂题目:到底有多少块岛屿 。按照题目的说法,并非是一个陆地的上下左右都有陆地,围成的才是岛屿。而是所有陆地都连在一起的才是一块岛屿(这些陆地之间没有海洋隔开)。
所以是两块岛屿。
2. 如何简单的判断岛屿会不会淹没:
①.进行思维转换,这道题可以想成 记录岛屿边的点数和总的点数,如果相等就是全是边,那么必然会被全淹没,否则不会。最后统计一下个数就行了
②.求的是被淹没的岛屿的数量=总岛屿数量-没淹没的岛屿的数量,如果一块岛屿里面的某一块陆地的四面都是陆地,那这个岛屿不会被淹没。注意:这样想有个误区,求没被淹没的岛屿容易出错,容易形成新的岛屿。比如下面这个图:
(一开始有两座岛屿,后来又是两座岛屿,这样求出的被淹没的岛屿数量就是错的)
(我不确定这样想是不是错的,如有错请指出)
3. 针对前面的方法一记录岛屿边的点数和总的点数:如何计算边数
只要'#'的四周出现'.'那么这就是边。
易错点:
1. 读入的是字符啊,我的老天爷,调试到最后才发现这个错误。
①. 要把数组定义为char类型
②. 如果用scanf("%c",&map[i][j]); 还是会错误,要处理好换行getchar();
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%c",&map[i][j]);
}
getchar();
}
但奇怪的是蓝桥上可以通过所有测试点
acwing上他有些通不过,比如这个:
换成cin来输入
for(int i = 0;i < n;i ++)
for(int j=0;j<n;j++)
cin >> map[i][j];
2. bool st[N][N]; 这个用来标志哪一个数字搜过没有。
3. 一般都是for(int i=0;i<4;i++) 左,上,右,下搜索,并更新map数组,但是这里有点不一样。
①. 如果这样写(错误写法):会导致搜到'.'之后不会继续搜索了,递归进行不下去,周边的其他陆地还要搜索呢。
for(int i=0;i<4;i++) //左,上,右,下搜索
{
int nx=x+dx[i],ny=y+dy[i]; //更新
{
if(total==brick) //此刻遇到终点了
{
cnt++;
}
else if(map[nx][ny]=='.')
{
brick++;
break; //并且不要再搜了
}
else if(map[nx][ny]=='#'&&!st[x][y])
{
total++;
dfs(nx,ny);
}
}
}
②. 正确写法:要再重新走一次循环。
void dfs(int x,int y)
{
st[x][y]=true;
for(int i=0;i<4;i++) //左,上,右,下搜索
{
if(map[x+dx[i]][y+dy[i]]=='.')
{
brick++;
break; //并且不要再搜了
}
}
for(int i=0;i<4;i++)
{int nx=x+dx[i],ny=y+dy[i]; //更新
if(map[nx][ny]=='#'&&!st[nx][ny])
{
total++;
dfs(nx,ny);
}
}
}
4. 不能把if(total==brick)
cnt++;
也放到bfs的for循环里面,如果实际total>brick的话,也会在某个时间判断成total==brick
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1010;
char map[N][N];
//int d[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};//左,上,右,下
const int dx[] = {-1,0,1,0}, dy[] = {0,-1,0,1};//左,上,右,下
bool st[N][N]; // 这个用来标志哪一个数字搜过没有
int total,brick,cnt=0;
void dfs(int x,int y)
{
st[x][y]=true;
for(int i=0;i<4;i++) //左,上,右,下搜索
{
if(map[x+dx[i]][y+dy[i]]=='.')
{
brick++;
break; //并且不要再搜了
}
}
for(int i=0;i<4;i++)
{int nx=x+dx[i],ny=y+dy[i]; //更新
if(map[nx][ny]=='#'&&!st[nx][ny])
{
total++;
dfs(nx,ny);
}
}
}
int main()
{
int n;
scanf("%d",&n);
/*for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%c",&map[i][j]); */
for(int i = 0;i < n;i ++)
for(int j=0;j<n;j++)
cin >> map[i][j];
// int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(map[i][j]=='#'&&!st[i][j])
{
brick=0;
total=1;
dfs(i,j);
if(total==brick)
cnt++;
}
}
cout << cnt << endl;
return 0;
}
优化代码:主要优化total的位置,其实不修改也行。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1010;
char map[N][N];
//int d[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};//左,上,右,下
const int dx[] = {-1,0,1,0}, dy[] = {0,-1,0,1};//左,上,右,下
bool st[N][N]; // 这个用来标志哪一个数字搜过没有
int total,brick,cnt=0;
void dfs(int x,int y)
{
total++;
st[x][y]=true;
for(int i=0;i<4;i++) //左,上,右,下搜索
{
if(map[x+dx[i]][y+dy[i]]=='.')
{
brick++;
break; //并且不要再搜了
}
}
for(int i=0;i<4;i++)
{int nx=x+dx[i],ny=y+dy[i]; //更新
if(map[nx][ny]=='#'&&!st[nx][ny])
{
dfs(nx,ny);
}
}
}
int main()
{
int n;
scanf("%d",&n);
/*for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%c",&map[i][j]); */
for(int i = 0;i < n;i ++)
for(int j=0;j<n;j++)
cin >> map[i][j];
// int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(map[i][j]=='#'&&!st[i][j])
{
total=brick=0;
dfs(i,j);
if(total==brick)
cnt++;
}
}
cout << cnt << endl;
return 0;
}