并查集-检查网络

【问题描述】

给定一个计算机网络以及机器间的双向连线列表,每一条连线允许两端的计算机进行直接的文件传输,其他计算机间若存在一条连通路径,也可以进行间接的文件传输。请写出程序判断:任意指定两台计算机,它们之间是否可以进行文件传输?

【输入要求】

输入若干测试数据组成。对于每一组测试,第1行包含一个整数N(≤10000),即网络中计算机的总台数,因而每台计算机可用1到N之间的一个正整数表示。接下来的几行输入格式为I C1 C2或者 C或者C C1C2或者S,其中C1和C2是两台计算机的序号,I表示在C1和C2间输入一条连线,C表示检查C1和C2间是否可以传输文件,S表示该组测试结束。当N为0时,表示全部测试结束,不要对该数据做任何处理。

【输出要求】

对每一组C开头的测试,检查C1和C2间是否可以传输文件,若可以,则在一行中输出“yes”,否则输出“no”。当读到S时,检查整个网络。若网络中任意两机器间都可以传输文件,则在一行中输出“The network is connected.”,否则输出“There are k components.”,其中k是网络中连通集的个数。两组测试数据之间请输出一空行分隔。

#include <iostream>
using namespace std;
#define MAX_N 10001

int par[MAX_N];		// 父亲 
int rank[MAX_N];	// 树的高度 

// 初始化n个元素
void init(int n)
{
	for(int i = 1; i <= n; ++ i)
	{
		par[i] = i;
		rank[i] = 0;
	}
} 

// 查询树的根
int find(int x)
{
	if(par[x] == x)
		return x;
	else
		return par[x] = find(par[x]);
		
} 

// 合并x和y所属的集合
void unite(int x, int y)
{
	x = find(x);
	y = find(y);
	if(x == y)
		return ;
	
	if(rank[x] > rank[y])
	{
		par[y] = x;
	}
	else
	{
		par[x] = y;
		if(rank[x] == rank[y])
		{
			rank[x] ++;
		}
	}
} 

// 判断x和y是否属于同一个集合
bool same(int x, int y)
{
	return find(x) == find(y);
} 

int main()
{
	// num 为机器总数, m1, m2 为任意两台机器 
	int num, m1, m2;
	// command为指令 
	char command;
	
	cout << "请输入机器总数:" << endl; 
	while(cin >> num)
	{
		// 当N为0时,表示全部测试结束,不要对该数据做任何处理。
		if(num == 0)
			break;
		if(num < 1 || num > MAX_N)
		{
			cout << "数据越界, 请重新输入" << endl;
			continue; 
		}
		
		// 并查集开始 
		init(num);	
	
		cout << "请输入指令:" << endl;
		while(cin >> command)
		{	
			
			// 错误指令的处理 
			if(command != 'S' && command != 'C' && command != 'I')
			{
				cout << "指令错误, 请重新输入" << endl;
				continue;
			}
			
			// 当读到S时,检查整个网络。
			// 若网络中任意两机器间都可以传输文件,则在一行中输出"The network is connected." 
			// 否则输出"There are k components."
			if(command == 'S')
			{
				int count = 0;
				for(int i = 1; i <= num; ++ i)
				{
					if(par[i] == i)
						count ++;
				}
				if(count == 1)
				{
					cout << "The network is connected." << endl;
				}
				else
				{
					cout << "There are " << count << " components." << endl;
				}
				
				cout << endl; 
				cout << "请输入机器总数:" << endl; 
				break;
			}
			
			// 输入两个机器 
			// cout << "请输入两个机器编号:" << endl; 
			cin >> m1 >> m2;
			
			// C开头的测试,检查C1和C2间是否可以传输文件
			// 若可以,则在一行中输出"yes",否则输出"no"。
			if(command == 'C')
			{
				if(same(m1, m2)) 
				{
					cout << "yes" << endl;
				}
				else
				{
					cout << "no" << endl;
				}
				
				cout << "请输入指令:" << endl;
			}
			
			// I表示在C1和C2间输入一条连线
			if(command == 'I')
			{
				unite(m1, m2);
				
				cout << "请输入指令:" << endl;
			}
		}
	}
	
	return 0;
}

/*
请输入机器总数:
3
请输入指令:
I 3 1
请输入指令:
I 2 3
请输入指令:
C 1 2
yes
请输入指令:
S
The network is connected.

请输入机器总数:
3
请输入指令:
C 1 2
no
请输入指令:
I 1 2
请输入指令:
C 1 2
yes
请输入指令:
S
There are 2 components.
*/

  

原文地址:https://www.cnblogs.com/mjn1/p/10893570.html