05-树8 File Transfer(并查集的路径压缩和按规模归并)

05-树8 File Transfer

  • 原题链接
  • 解题思路
  • 源代码

原题链接

树(下)课后练习题2

解题思路

并查集的基本实现与应用,外加路径压缩和按秩归并,按秩归并有按高度归并和按规模归并两种,我更喜欢按规模,就是元素个数嘛。

之前不知道要归并,以为路径压缩了就完事大吉了,并查集用数组father[]实现,如果father[i] = i表示i是根结点,第一种写法没考虑归并,把father值都插入set中计算连通块个数。

//仅路径压缩
#include
#include
using namespace std;
const int maxn = 100010;
int father[maxn];
set<int> res;//记录根结点,为了统计有几个集合 
int findFather(int x){
	int a = x;
	while(x != father[x]){
		x = father[x];
	}
	//记录根结点,路径压缩
	int root = x;
	while(a != father[a]){
		int z = a;
		a = father[a];
		father[z] = root;
	} 
	return root;
} 
void Union(int a, int b){
	//按秩归并,将规模小的集合指向规模大的集合
	
}
int main(){
	char ch;
	int n, a, b;
	scanf("%d", &n);
	//init
	for(int i=1; i<=n; i++){
		father[i] = i;
	} 
	getchar();
	//注意不要让ch读成换行 
	while(scanf("%c", &ch)){
		if(ch == 'S')
			break;
		scanf("%d%d", &a, &b);
		getchar();
		int faA = findFather(a);
		int faB = findFather(b);
		if(ch == 'I'){
			//如果不属于一个集合,就合并这两个元素所在集合 
			Union(faA, faB);
		}
		else if(ch == 'C'){
			if(faA == faB)
				printf("yes\n");
			else
				printf("no\n"); 
		}
	} 
	//计算有几个集合
	for(int i=1; i<=n; i++){
		res.insert(father[i]);
	}
	if(res.size() == 1){
		printf("The network is connected.\n");
	}
	else{
		printf("There are %d components.\n", res.size());
	}
	return 0;
}

源代码

要实现按规模归并,只要重新给根结点的father值赋更合理的值即可,就是该集合中元素个数啦。

//按秩归并
#include
#include
using namespace std;
const int maxn = 100010;
int father[maxn];
//set res;//记录根结点,为了统计有几个集合 
int findFather(int x){
	int a = x;
	while(father[x] > 0){
		x = father[x];
	}
	//记录根结点的下标,路径压缩
	int root = x;
	while(father[a] > 0){
		int z = a;
		a = father[a];
		father[z] = root;
	} 
	return root;
} 
void Union(int a, int b){
	//按秩归并,将规模小的集合指向规模大的集合
	if(father[a] < father[b]) {
		//b的规模更小 -2 < -1
		father[a] += father[b];
		father[b] = a; 
	}
	else{
		father[b] += father[a];
		father[a] = b;
	}
}
int main(){
	char ch;
	int n, a, b;
	scanf("%d", &n);
	//init
	for(int i=1; i<=n; i++){
		father[i] = -1;
	} 
	getchar();
	//注意不要让ch读成换行 
	while(scanf("%c", &ch)){
		if(ch == 'S')
			break;
		scanf("%d%d", &a, &b);
		getchar();
		int faA = findFather(a);
		int faB = findFather(b);
		if(ch == 'I'){
			//如果不属于一个集合,就合并这两个元素所在集合 
			Union(faA, faB);
		}
		else if(ch == 'C'){
			if(faA == faB)
				printf("yes\n");
			else
				printf("no\n"); 
		}
	} 
	int res = 0; 
	//计算有几个集合
	for(int i=1; i<=n; i++){
		if(father[i] < 0){
			res++;
		}
	}
//	for(int i=1; i<=n; i++){
//		res.insert(father[i]);
//	}
	if(res == 1){
		printf("The network is connected.\n");
	}
	else{
		printf("There are %d components.\n", res);
	}
	return 0;
}

你可能感兴趣的:(数据结构)