连通块问题

判断一个二位数组有几个连通块,八领域都表示连通。用@表示连通块。

输入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;
}

猜你喜欢

转载自blog.csdn.net/Apro1066/article/details/81775749