1. 程式人生 > >並查集(按秩合併、路徑壓縮)

並查集(按秩合併、路徑壓縮)

演算法分類:

資料結構

演算法原理:

通過find函式找出該節點的根節點,

通過UNION函式將兩棵樹合併。

加入rank[N]來記錄每個節點的秩(即樹的高度),並按秩進行合併,可避免合併時的最糟糕情況,(樹形為一條直線)

通過路徑壓縮可以減少每次尋找根節點的次數。

演算法時間複雜度:

最壞情況為O(mlogn)

一般為O(m)

程式碼實現:(HDU1232-暢通工程)

/*
 * HDU 1232 暢通工程
 * 並查集
 */ 
#include <iostream>
using namespace std;

const int SIZE = 1005;
int root[SIZE];
int rank[SIZE];

int find(int x) {
	int y = x;
	while (root[y] != y) {
		y = root[y];	
	}
	
	int temp, head = y;
	y = x;
	while (root[y] != y) {
		temp = root[y];
		root[y] = head;
		y = temp;	
	}
	
	return head;
};

void UNION(int x, int y) {
	int f1 = find(x);
	int f2 = find(y);
	
	if (rank[f1] <= rank[f2]) {
		root[f1] = f2;
		if (rank[f1] == rank[f2]) {
			rank[f2] ++; 	
		}	
	} else {
		root[f2] = f1;
	}
};

int main()
{
	int N, M, s, e, count;
	
	while (scanf("%d%d",&N,&M)!=EOF, N) {
		for (int i = 1; i <= N; ++ i) 
			root[i] = i;
		
		for (int i = 0; i < M; ++ i) {
			scanf("%d%d",&s,&e);
			UNION(s,e);
		}
		
		count = -1;
		for (int i = 1; i <= N; ++ i) {
			if (root[i] == i) 
				++ count;
		}
		
		printf("%d\n",count);
	}
}