您的位置:首页 > 汽车 > 新车 > 蓝桥杯2023(十四届)省赛——岛屿个数(DFS+BFS)

蓝桥杯2023(十四届)省赛——岛屿个数(DFS+BFS)

2024/12/29 9:25:07 来源:https://blog.csdn.net/Caspiannn/article/details/139258483  浏览:    关键词:蓝桥杯2023(十四届)省赛——岛屿个数(DFS+BFS)

岛屿个数(DFS+BFS)

1.岛屿个数 - 蓝桥云课 (lanqiao.cn)

**法一:**本题很妙啊,你发现没有。反向操作,不是直接算岛屿数量,而是先将最外层的海洋给标注出来(DFS,visit[i][j]=2),然后再用一次DFS把所有visit[i][j]=0的当做整体,这些不管里面有没有子岛屿,有多少个子岛屿,都是一个大岛屿。

本题你可以学到的:标记海洋(八方、只遍历最外面一圈)、标记岛屿(四方、无回溯(因为我们要全部标记,不是找路径))

**法二:**这里提供一个思路,在评论区看到另一个大佬写的:搜索出所有岛屿,这个不难做到。由于岛屿之间互相隔离,则如果岛屿的一个格子在一个环内,那么整个岛屿也都在环内。遍历所有的岛屿,选中当前岛屿的第一个格子,搜索周围海洋,若能搜索到地图的边界外,则此岛屿不在任何一个环内;否则,此岛屿在某个环内,岛屿数量减一。

这个思路和我做的方法区别在于,我是从外向内,而该思路是正向思考,然后利用内岛的性质,对整体做出进一步加工。

下面给出法一的代码:

AC:DFS

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
//牛的,我是真的没想到,可以反向操作,不好求里面,那就求外面,把外层海水搜素出来,
// 这样剩下的不管有没有內岛屿,都是一个岛屿	他们用的是bfs,我这里用dfs试试,应该也可以
//注意,检索海水和检索岛屿不一样,海水是八方搜索,而岛屿是四方搜素const int N = 105;
int t, n, m;	//m行 n列
int nx[4] = { 0,1,0,-1 };
int ny[4] = { 1,0,-1,0 };
int seax[8] = { 0,1,1,1,0,-1,-1,-1 };
int seay[8] = { 1,1,0,-1,-1,-1,0,1 };
vector<string>g;
int visit[N][N] = { 0 };
int landNum = 0;void dfs(int x, int y)
{for (int i = 0; i < 8; i++){int xx = x + seax[i];int yy = y + seay[i];if (xx < 0 || xx >= m || yy < 0 || yy >= n)	continue;	//越界if (g[xx][yy] == '0' && visit[xx][yy] == 0){visit[xx][yy] = 2;dfs(xx, yy);//visit[xx][yy] = 0;	//回溯}}
}void dfsLand(int x, int y)
{for (int i = 0; i < 4; i++){int xx = x + nx[i];int yy = y + ny[i];if (xx < 0 || xx >= m || yy < 0 || yy >= n)	continue;	//越界if (visit[xx][yy] == 0)	//接下来就和g的值无关了{visit[xx][yy] = 1;dfsLand(xx, yy);}}
}int main()
{cin >> t;while (t--){g.clear();memset(visit, 0, sizeof(visit));landNum = 0;cin >> m >> n;getchar();string str;for (int i = 0; i < m; i++){getline(cin, str);g.push_back(str);}//检索海洋//for (int i = 0; i < n; i++)//{//	for (int j = 0; j < m; j++)//	{//		if (g[i][j] == '0' && visit[i][j] == 0)	//		{//			visit[i][j] = 2;	//最外层海水 标记为2//			dfs(i,j);//		}//	}//}		//这样标记海水不是最外层的,而是所有//要标记外海,其实只需要遍历最外面的一圈for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){if (i == 0 || j == 0 || i == m - 1 || j == n - 1){if (g[i][j] == '0' && visit[i][j] == 0){visit[i][j] = 2;	//最外层海水 标记为2dfs(i, j);}}}}//检索岛屿for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){if (visit[i][j] == 0)	//剩下的都是岛屿{landNum++;visit[i][j] = 1;	//陆地 标记为1dfsLand(i, j);}}}cout << landNum << endl;}return 0;
}

二刷:思路和一刷差不多,这里用的BFS,主要是代码方面有些许差别大家可以选择容易理解的。
BFS:

//岛屿个数
#include <iostream>
#include <cstring>
#include <queue>
#include <string>
using namespace std;//思路:正难则反,我们先不统计岛屿的个数,先将所有的外海标记,那么剩下的没有标记的就是岛屿
//注意,海水是8方走 const int N=53;
int g[N][N]={0};		//0海 1陆 
int book[N][N]={0};		//1表示已经遍历过 
int n,m,k;
int mx[8]={-1,-1,0,1,1,1,0,-1};
int my[8]={0,1,1,1,0,-1,-1,-1};
int imx[4]={0,0,1,-1};
int imy[4]={1,-1,0,0};struct Pos
{int x,y;
};bool isOut(int x,int y)
{if(x<0 || x>=m || y<0 || y>=n)	return true;	//确实出界了if(g[x][y]==1)	return true;	//陆地,不能走return false;	//没有出界 
}bool islandOut(int x,int y)
{if(x<0 || x>=m || y<0 || y>=n)	return true;	//确实出界了//注意这里不需要再判断是否为海洋了,因为我们将这块岛屿内海也视为岛屿 return false;	//没有出界 
}void bfs_island(int x,int y)
{queue<Pos>q;q.push({x,y});book[x][y]=1; while(!q.empty()){Pos cur=q.front();q.pop();for(int i=0;i<4;i++){Pos nex;nex.x=imx[i]+cur.x;nex.y=imy[i]+cur.y;if(islandOut(nex.x,nex.y) || book[nex.x][nex.y]==1)	continue;book[nex.x][nex.y]=1; q.push(nex);}}
}void bfs_sea(int x,int y)
{queue<Pos>q;q.push({x,y});book[x][y]=1;while(!q.empty()){Pos cur=q.front();q.pop();for(int i=0;i<8;i++){Pos nex;nex.x=mx[i]+cur.x;nex.y=my[i]+cur.y;if(isOut(nex.x,nex.y) || book[nex.x][nex.y]==1)	continue;book[nex.x][nex.y]=1; q.push(nex);}}
}int main()
{cin>>k;while(k--){cin>>m>>n;int ans=0;memset(book,0,sizeof(book));memset(g,0,sizeof(g));string str;for(int i=0;i<m;i++){cin>>str;for(int j=0;j<n;j++){if(str[j]=='1')g[i][j]=1;}}for(int i=0;i<n;i++)	//第一行 if(g[0][i]==0 && book[0][i]==0)bfs_sea(0,i);for(int i=0;i<m;i++)	//第一列 if(g[i][0]==0 && book[i][0]==0)bfs_sea(i,0);	for(int i=0;i<n;i++)	//第m-1行 if(g[m-1][i]==0 && book[m-1][i]==0)bfs_sea(m-1,i);for(int i=0;i<m;i++)	//第n-1列 if(g[i][n-1]==0 && book[i][n-1]==0)bfs_sea(i,n-1);for(int i=0;i<m;i++)for(int j=0;j<n;j++){if(book[i][j]==0)	//没标记的,就是岛屿{ans++;bfs_island(i,j); }	}cout<<ans<<endl;}return 0;} 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com