判断一个二位数组有几个连通块,八领域都表示连通。用@表示连通块。
输入n,m,表示地图大小,接下来输入地图,问这个由@组成的连通块有多少个。
样例输入:
10 12
@........@..
.@@@.....@@@
....@@...@@.
.........@@.
.........@..
..@......@..
.@.@.....@@.
@.@.@.....@.
.@.@......@.
..@.......@.
样例输出:
3
Code
模版1:bfs
//广度优先搜索,bfs
#include <stdio.h>
#include <iostream>
using namespace std;
int tox[9]={0,1,0,-1,0,1,1,-1,-1};//8个方向
int toy[9]={0,0,1,0,-1,-1,1,1,-1};
int n,m,s,que[40001][4];//n,m地图大小,s为连通块数,que为队列
char a[201][201];//地图
inline void bfs(int x,int y)//x,y当前坐标点
{
int head(1),tail(1);
register int i;
que[tail][1]=x;//第一个坐标入队
que[tail][2]=y;
a[x][y]='.';//覆盖第一个坐标,以免回到起点
tail++;//第一个入队过了,尾指针+1
while(head<tail)//直到队空为止
{
int qx=que[head][1];//头指针的坐标给队列坐标
int qy=que[head][2];
for(i=1;i<=8;i++)//搜索8个方向
{
int x1=qx+tox[i];//尝试下一个坐标
int y1=qy+toy[i];
if(x1>0 && x1<=n && y1>0 && y1<=m && a[x1][y1]=='@')//1.还在地图内2.是@块
{
a[x1][y1]='.';//覆盖掉,不然重复搜索。也可以用一个数组来标记
que[tail][1]=x1;//搜索到的点入怼
que[tail][2]=y1;
tail++;//尾指针加1
}
}
head++;
}
return;
}
int main()
{
ios::sync_with_stdio(false);
register int i,j;
cin>>n>>m;//输入地图大小
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>a[i][j];//输入地图
}
}
for(i=1;i<=n;i++)//搜索地图
{
for(j=1;j<=m;j++)
{
if(a[i][j]=='@')//找到了为@的
{
s++;//连通块数+1
bfs(i,j);//搜索相连的块@
}
}
}
cout<<s<<endl;//输出连通块数
return 0;
}
模版2:dfs(数据过大会爆栈)
//深度优先搜索,dfs--<个人认为比较好理解>
#include <stdio.h>
#include <iostream>
using namespace std;
int tox[9]={0,1,0,-1,0,1,1,-1,-1};//8个方向
int toy[9]={0,0,1,0,-1,-1,1,1,-1};
int n,m,s;//n,m地图大小,s为连通块数
char a[201][201];//地图
inline void dfs(int x,int y)//x,y当前坐标点
{
register int i,j;
a[x][y]='.';//当前坐标点标记为'.',表示已经搜索过,否则会重复搜,当然可以用一个数组来标记
for(i=1;i<=8;i++)//搜索8个方向
{
int x1=x+tox[i];//尝试下一个坐标
int y1=y+toy[i];
if(x1>0 && x1<=n && y1>0 && y1<=m && a[x1][y1]=='@')////1.还在地图内 2.是@块
{
dfs(x1,y1);//搜是否有下一个
}
}
return;
}
int main()
{
ios::sync_with_stdio(false);
register int i,j;
cin>>n>>m;//输入地图大小
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>a[i][j];//输入地图
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(a[i][j]=='@')//从@开始尝试搜索
{
s++;//连通块+1
dfs(i,j);//开始搜索
}
}
}
cout<<s<<endl;//输出连通块数
return 0;
}
模版3:并查集寻找连通块节点数
#include <stdio.h>
#include <iostream>
using namespace std;
int n,m,p[4001],s;//p保存节点的直接父节点
inline int find(int x)//查找x的根节点
{
if(p[x]!=x)
p[x]=find(p[x]);
return a[x];
}
inline void join(int x,int y)//连接两个连通块
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
p[fy]=fx;
}
}
int main()
{
ios::sync_with_stdio(false);
register int i,j;
cin>>n>>m;
for(i=1;i<=n;i++)
{
p[i]=i;//初始化p数组
}
for(i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
join(x,y);
}
for(i=1;i<=n;i++)
{
if(p[i]==i)
s++;//计算连通子图的个数s
}
cout<<s<<endl;
return 0;
}