球迷(数据结构作业)

版权声明:未经本人同意,禁止转载。 https://blog.csdn.net/qq_34022601/article/details/84147373

算法与数据结构实验题 12.2  球迷

 

★实验任务

在福大里,有 n 个学生,每个的学生都有自己喜爱的球星,已知有 m 对学生喜爱的球星相同,问你这 n 个学生喜爱的球星最多有多少个。

★数据输入

输入第一行为一个正整数 n,m。

接下来 m 行,每行输入 ai,bi,表示 ai 同学和 bi 同学喜爱的球星一样

80%的数据 1<=n,m<=1000.

100%的数据 1<=n,m<=100000.

★数据输出

输出一个正整数,表示答案。

 

输入示例

输出示例

10 9

1

1 2

 

1 3

 

1 4

 

1 5

 

1 6

 

1 7

 

1 8

 

1 9

 

1 10

 

 

输入示例

输出示例

10 4

7

2 3

 

4 5

 

4 8

 

5 8

 

 

两个方法本质相同:BFS求连通性,并查集求连通性.

方法一:

这道题是典型的图的搜索算法(BFS).用邻接矩阵实现的话,时间复杂度为O(N+E).

思路:
有着相同喜欢的球星的同学连在一起,形成一个连通子块。其他的同学作为独立点(特殊子块)。求共有多少个连通子块?

依据BFS的算法,对从1-n的每一个点遍历。

#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
/*
结构体+可变数组 模拟邻接矩阵 
*/ 
struct Graph{
	vector <int> v;
};
Graph g[100100];		//图的数组 
int turn [100100]={0};	//BFS过程中的标记数组。 
void BFS(int i)
{
	int x;
	queue <int> q;
	q.push(i);
	vector <int> :: iterator it;
	//对节点i,BFS,把和i连在一起的都遍历一遍。 
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		turn[x]++;
		for (it=g[x].v.begin();it!=g[x].v.end();it++)
		{
			if (turn[*it]==0)
			{
				q.push(*it);
			}
		}
	}
}
int main()
{
	int n,m,x,y,count=0;
	scanf ("%d %d",&n,&m);
	for (int i=0;i<m;i++)
	{
		scanf ("%d %d",&x,&y);
		g[x].v.push_back(y);
		g[y].v.push_back(x);
	}
	for (int i=1;i<=n;i++)
	{
		if (g[i].v.empty())
		{
			count++;
			turn[i]++;
		}
		else
		{
			if (turn[i]==0)
			{
				count++;
				BFS(i);
			}
		}
	}
	printf ("%d\n",count);
	return 0;
} 

方法2:

经典并查集模型

 

#include <cstdio>
#include <cstring>
using namespace std;
int s[100010];
int count;
void Make_Set(void)
{
	memset(s,-1,sizeof(s));			//初始化所有节点 
}
int Find(int x)
{ 
	if (s[x]<=0)					//找到根节点,返回 
		return x;
	else
		return (s[x]=Find(s[x]));	//路径压缩,把x到根节点的路径上的所有节点变成根的儿子 
}
void Union(int root1,int root2)		//按秩求并 
{
	root1=Find(root1);
	root2=Find(root2);
	if (root1==root2)	//两节点连通,退出 
		return ;
	if (s[root2]<s[root1])			//root2树更深,把root1合并到root2 
		s[root1]=root2;
	else{
		if (s[root1]==s[root2])		//相同高度,合并root1高度+1 
			s[root1]--;	
		s[root2]=root1;				//root2合并到root1 
	}
	count--;						//由于两集合合并,所有子树数量-1 
}
int main()
{
	int n,m,a,b,ra,rb;
	scanf ("%d %d",&n,&m);
	count=n;
	Make_Set();
	for (int i=0;i<m;i++)
	{
		scanf ("%d %d",&a,&b);
		Union(a,b);
	}
	printf ("%d\n",count);
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/qq_34022601/article/details/84147373