1. 程式人生 > >球迷(資料結構作業)

球迷(資料結構作業)

演算法與資料結構實驗題 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;
}