05-树8 File Transfer 并查集(按秩归并+路径压缩)

复杂度分析
https://blog.csdn.net/Estia_/article/details/86708289

e have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?

Input Specification:
Each input file contains one test case. For each test case, the first line contains N (2≤N≤10
​4
​​ ), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:

I c1 c2  

where I stands for inputting a connection between c1 and c2; or

C c1 c2    

where C stands for checking if it is possible to transfer files between c1 and c2; or

S

where S stands for stopping this case.

Output Specification:
For each C case, print in one line the word “yes” or “no” if it is possible or impossible to transfer files between c1 and c2, respectively. At the end of each case, print in one line “The network is connected.” if there is a path between any pair of computers; or “There are k components.” where k is the number of connected components in this network.

Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S

      
    
Sample Output 1:
no
no
yes
There are 2 components.

      
    
Sample Input 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S

      
    
Sample Output 2:
no
no
yes
yes
The network is connected.
主要思想:
1 按秩归并:1比较树高度归并 2 比较树规模归并 这里采用后者 后者配合路径压缩更好因为路径压缩会改变树高
2 数组根节点(老大)的值存有多少个节点(小弟+自己)的负数,而小弟结点的值是指向老大的值(正数)
#include<iostream>                                   
using namespace std;
int set[10001];
void Union(int s[], int root1,int root2)           
{												   //将数组根节点(老大)的值存有多少个节点(小弟+自己)的负数
	if (s[root2] < s[root1]) {                     //如果集合2比集合规模1大,1并入2中
		s[root2] += s[root1];
		s[root1] = root2;  
	}
	else {
		s[root1] += s[root2];						//如果集合1比集合规模2大,2并入1中
		s[root2] = root1;
	}
}
int find(int s[], int x)
{
	if (s[x] < 0)                                    //指向的父亲结点的值记录着个数的负数
		return x;									 //返回根节点的下标
	else
		return s[x] = find(s, s[x]);                 //递归,路径压缩,使得下次判断查找根节点十分方便
	                                                 //给每个结点都指向他的根节点,一路上都会被压缩
}
int main()
{
	int n;
	int num = 0;
	int computerA, computreB;
	cin >> n;
	for (int i = 0; i < n + 1; i++)
		set[i] = -1;                                      //一开始都是只有自己1个结点,所以为-1
	char input;
	while (cin >> input&&input != 'S') {
		if (input == 'I') {
			cin >> computerA >> computreB;
			Union(set, find(set, computerA), find(set, computreB));
		}else if (input == 'C') {
			cin >> computerA >> computreB;
			if (find(set, computerA) == find(set, computreB))
				cout << "yes" << endl;
			else
				cout << "no" << endl;
		}
	}
	for (int i = 1; i < n + 1; i++) {
		if (set[i] < 0)
			num++;
	}
	if (num == 1)
		cout << "The network is connected." << endl;
	else
		cout << "There are " << num << " components." << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/Hsiung123/p/13109999.html