NOI 4.3 图论 1526:宗教信仰

题目来源:http://noi.openjudge.cn/ch0403/1526/

1526:宗教信仰

总时间限制5000ms    内存限制65536kB

描述

世界上有许多宗教,你感兴趣的是你学校里的同学信仰多少种宗教。

你的学校有n名学生(0 < n <= 50000),你不太可能询问每个人的宗教信仰,因为他们不太愿意透露。但是当你同时找到2名学生,他们却愿意告诉你他们是否信仰同一宗教,你可以通过很多这样的询问估算学校里的宗教数目的上限。你可以认为每名学生只会信仰最多一种宗教。

 

输入

输入包括多组数据。
每组数据的第一行包括nm0 <= m <= n(n-1)/2,其后m行每行包括两个数字ij,表示学生i和学生j信仰同一宗教,学生被标号为1n。输入以一行n = m = 0 作为结束。

输出

对于每组数据,先输出它的编号(从1开始),接着输出学生信仰的不同宗教的数目上限。

样例输入

10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
10 4
2 3
4 5
4 8
5 8
0 0

样例输出

Case 1: 1
Case 2: 7

 -----------------------------------------------------

思路

题意:已知图中节点的连接关系,求图中的连通支数量。

并查集模板题。关于并查集的详细介绍,可以看这篇神奇的博文一个很有意思的并查集详解

-----------------------------------------------------

代码 

// 并查集

#include<iostream>
#include<fstream>
using namespace std;

const int NMAX = 50005;
int pre[NMAX] = {};								// 每个节点的父节点
int n = -1;										// 全局变量:学生人数
int cnt = n;									// 全局变量:总的集合个数

int find(int x)									// 输入一个节点的编号,返回该节点在并查集中的根节点
{
	int r = pre[x],t = x;
	while (r!=t)								// 如果不是根节点(父节点==自己),则不断上溯
	{
		t = r;
		r = pre[t];
	}
	// 路径压缩过程
	t = x;
	int tt = x;
	while (t!=r)								// 从叶子节点开始回溯,把路径上的所有节点的父节点全都设为根节点
	{
		tt = pre[t];
		pre[t] = r;
		t = tt;
	}

	return r;
}

void join(int x, int y)							// 合并两个元素所在集合
{
	int xx = find(x), yy = find(y);				// 分别找到两个元素的根节点
	if ( xx!= yy)								// 如果两个元素的根节点不同, 则需要合并; 否则两个元素本来就在同一个集合
	{
		cnt--;									// 总的集合个数-1
		pre[xx] = yy;							// 将一个集合的根节点的父节点设为另一个集合的根节点
	}
}



int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0403_1526.txt");
	int m,i,x,y,t=0;
	while (fin >> n >> m)
	{
		if (n==0 && m==0)
		{
			break;
		}
		for (i=0; i<n; i++)
		{
			pre[i] = i;
		}
		cnt = n;
		for (i=0; i<m; i++)
		{
			fin >> x >> y;
			join(x,y);
		}
		cout << "Case "<< (++t) << ": " << cnt << endl;
	}
	fin.close();
#endif
#ifdef ONLINE_JUDGE
	int m,i,x,y,t=0;
	while (cin >> n >> m)
	{
		if (n==0 && m==0)
		{
			break;
		}
		for (i=0; i<n; i++)
		{
			pre[i] = i;
		}
		cnt = n;
		for (i=0; i<m; i++)
		{
			cin >> x >> y;
			join(x,y);
		}
		cout << "Case "<< (++t) << ": " << cnt << endl;
	}
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80738108
4.3