注意点:
1.怪不得这么多佬都喜欢用字符读01,因为int读得处理一下
当输入是010111串时,用int读,只算一个int
解决方法:scanf("%1d",...),只读入一个整数
2.bfs时,记得每输入一个图,将标记置为false
memset(u,0,sizeof u); //#include<cstring>
分析
1.不加条件“不包括环内岛屿”,则是经典的求岛屿数量题目,直接dfs or bfs
2.加了条件,本题在按经典求解方法求出后,还需要判断是否是子岛屿
3.如何判断:
在输入图之前,手动增加一圈外海,从外海开始遍历图,那么该岛屿一定不是环内岛屿
BFS求解
从起点开始找:
(1)是海,入队,标记
(2)不是海,标记为岛屿,岛屿数量+1
bfs一般用队列实现
1.经典求岛屿个数代码
void bfs_island(int x,int y) //从起点开始
{
queue<PII> q;
q.push({x,y}); //入队
u[x][y] = true; //标记已访问
while(!q.empty()) //队不为空
{
PII p = q.front(); //取队首
q.pop(); //弹出队首
for(int i = 0;i < 4;i ++) //遍历上下左右,是否能组成一个岛
{
int a = p.first + dx[i];
int b = p.second + dy[i];
if((a>=1&&a<=m) && (b>=1&&b<=n) && g[a][b]==1 && !u[a][b]) //未超出边界,未访问,且是岛屿(中的一个点)
{
q.push({a,b}); //入队
u[a][b] = true; //标记已访问
}
}
}
}
2.本题解法
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 55;
typedef pair<int,int> PII;
bool u[N][N];
int g[N][N];
int t,n,m;
int dx[] = {1,-1,0,0,1,-1,-1,1};
int dy[] = {0,0,-1,1,1,1,-1,-1};
//遍历岛屿
void bfs_island(int x,int y)
{
queue<PII> q;
q.push({x,y});
u[x][y] = true;
while(!q.empty())
{
PII p = q.front();
q.pop();
for(int i = 0;i < 4;i ++)
{
int a = p.first + dx[i];
int b = p.second + dy[i];
if((a>=1&&a<=m) && (b>=1&&b<=n) && g[a][b]==1 && !u[a][b])
{
q.push({a,b});
u[a][b] = true;
}
}
}
}
//遍历外海
int bfs_sea(int x,int y)
{
int cnt = 0; //记录岛屿数量
queue<PII> q;
u[x][y] = true;
q.push({x,y});
while(!q.empty())
{
PII p = q.front();
q.pop();
for(int i = 0;i < 8;i ++) //遍历海要八个方向
{
int a = p.first + dx[i];
int b = p.second + dy[i];
if((a>=0&&a<=m+1) && (b>=0&&b<=m+1) && !u[a][b]) //未出界,未访问
{
if(g[a][b] == 0) //是海,入队,标记已访问
{
q.push({a,b});
u[a][b] = 1;
}
else //是陆地,找岛屿(将同属于一个岛屿的点标记为true),数量+1
{
bfs_island(a,b);
cnt ++;
}
}
}
}
return cnt;
}
int main()
{
scanf("%d",&t);
while(t --)
{
memset(u,0,sizeof u); //每次输入图将标记置false
scanf("%d %d",&n,&m);
//手动添加一圈外海
for(int i = 0;i < m + 2;i ++)
{
for(int j = 0;j < n + 2;j ++)
g[i][j] = 0;
}
//输入图
for(int i = 1;i < m + 1;i ++)
{
for(int j = 1;j < n + 1;j ++)
scanf("%1d",&g[i][j]);
}
int cnt = bfs_sea(0,0); //找岛屿数量
printf("%d\n",cnt);
}
return 0;
}
DFS求解
1.标记所有海
2.遍历图:
(1)从外海来的,且该点是岛屿,cnt ++
(2)不是,说明是子岛屿,不做处理
dfs可用栈和递归
1.经典求岛屿个数代码
//递归
void dfs_island(int x,int y)
{
if(x<1||x>m+1||y<1||y>n+1) return; //超出边界,返回
if(g[x][y] == 1) //是岛屿,接着找其上下左右的点
{
g[x][y] = 0; //1:岛屿;2:外海;0:内海
for(int i = 0;i < 4;i ++) dfs_island(x+dx[i],y+dy[i]);
}
return ;
}
2.本题目解法
#include<iostream>
using namespace std;
const int N= 55;
int dx[8]={-1,1,0,0,1,-1,-1,1},dy[8]={0,0,-1,1,1,1,-1,-1};
int g[N][N];
int t,n,m;
//置外海为2
void dfs_sea(int x,int y)
{
if(x<0||x>m+2||y<0||y>n+2) return; //超出边界
if(g[x][y] == 0)
{
g[x][y] = 2;
for(int i = 0;i < 8;i ++) dfs_sea(x+dx[i],y+dy[i]); //八个方向
}
return;
}
//置岛屿为0
void dfs_island(int x,int y)
{
if(x<1||x>m+1||y<1||y>n+1) return;
if(g[x][y] == 1)
{
g[x][y] = 0;
for(int i = 0;i < 4;i ++) dfs_island(x+dx[i],y+dy[i]);
}
return ;
}
int main()
{
scanf("%d",&t);
while(t --)
{
scanf("%d %d",&m,&n);
//手动添加一圈海
for(int i = 0;i < m + 2;i ++)
{
for(int j = 0;j < n + 2;j ++)
g[i][j] = 0;
}
//读入图
for(int i = 1;i < m + 1;i ++)
{
for(int j = 1;j < n + 1;j ++)
scanf("%1d",&g[i][j]); //划重点!!题目是以字符的形式输入,想用int读一位整数——%1d
}
dfs_sea(0,0);
int cnt = 0;
//遍历图
for(int i = 1;i < m + 1;i ++)
{
for(int j = 1;j < n + 1;j ++)
{
if(g[i][j] == 1 && g[i-1][j] == 2) //是岛屿且是可以是外海来的
{
cnt ++; //岛屿数量+1
dfs_island(i,j); //找到一个岛将其所有点置0
}
}
}
printf("%d\n",cnt);
}
return 0;
}
678

被折叠的 条评论
为什么被折叠?



