05-樹8 File Transfer(並查集的路徑壓縮和按規模歸併)

原題鏈接

樹(下)課後練習題2

解題思路

並查集的基本實現與應用,外加路徑壓縮和按秩歸併,按秩歸併有按高度歸併和按規模歸併兩種,我更喜歡按規模,就是元素個數嘛。

之前不知道要歸併,以爲路徑壓縮了就完事大吉了,並查集用數組father[]實現,如果father[i] = i表示i是根結點,第一種寫法沒考慮歸併,把father值都插入set中計算連通塊個數。

//僅路徑壓縮
#include<iostream>
#include<set>
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<iostream>
#include<set>
using namespace std;
const int maxn = 100010;
int father[maxn];
//set<int> 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章