並查集的分析及應用
昨天看了幾篇有關並查集的論文,對理解並查集很有幫助,在這裡寫篇部落格來記錄下自己對並查集的簡單理解,以及並查集的簡單運用。
並查集的分析
並查集的概念主要是處理集合問題(或可抽象成集合概念的問題),首先數學上的集合概念做個初步的分析
首先,我們從數學的角度給出等價關係和等價類的定義:
定義1:如果集合S中的關係R是自反的,對稱的,傳遞的,則稱他為一個等價關係。
——自反:x=x;
——對稱:若x=y,則y=x;
——傳遞:若x=y、y=z,則x=z。?要求:x、y、z必須要同一個子集中。
定義2:如果R是集合S的等價關係。對於任何x∈S,由[x]R={y|y∈S and xRy}給出的集合[x]RS
稱為由x∈S生成的一個R的等價類。
定義3:若R是集合S上的一個等價關係,則由這個等價關係可產生這個集合的唯一劃分。
即可以按R將S劃分為若干不相交的子集S1,S2,S3,S4,…,他們的並即為S,則這
些子集Si變稱為S的R等價類。
劃分等價類的問題的提法是:要求對S作出符合某些等價性條件的等價類的劃分,已知
集合S及一系列的形如“x等價於y”的具體條件,要求給出S的等價類的劃分,符合所
列等價性的條件。(我們上面提到的聯絡,即可認為是一個等價關係,我們就是要將
集合S劃分成n個聯絡的子集,然後再判斷x,y是否在一個聯絡子集中。)
這三個基本定義對理解並查集的概念及相應的操作非常有幫助。
並查集的操作主要有三個:
1.劃分等價類,這個在預處理的時候進行,很簡單,就是有多少元素就劃分多少等價類即pre[i]=i,很好理解,為下面的合併做好準備。
2.找根節點(溯源) 我通常用函式root(int x)來實現找x的最終祖先。
3.合併,就是將兩個集合合為一個集合。
用演算法實現三個方法:
1.預處理
void init(int n){
int i;
for(i=1;i<=n;++i){
pre[i] = i;
}
}
int root(int x){
if(x!=pre[x]){
pre[x] = root(pre[x]);
}
return pre[x];
}
溯源這裡是有優化的,判斷兩個元素是否屬於同一集合需要O(n)的時間,但這裡可以使用路徑壓縮來進行優化, 路徑壓縮實際上是在找完根結點之後,在遞迴回來的時候順便把路徑上元素的父親指標都指向根結點
3.合併
void merge(int a,int b){
int x = root(a);
int y = root(b);
if(x!=y){
pre[x]=y;
}
}
合併就是先找到a和b各自的源,然後把源連起來則兩個集合就實現了合併。
一上這三個函式就是並查集的核心思想和方法,以後的解題關鍵就是能將問題抽象成集合並應用並查集來解決了。
並查集的應用
下面我們就以以上並查集的思想解決一個實際問題來簡單運用一下。
以解決 HDU 1232為例。
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1232
題目在這裡就不再贅述了,經過上面的分析,此題就變的很簡單了。
N個頂點連通至少需要N-1條邊,這個是學計算機的都曉得的基礎知識(樹)。此問題總需要的最少邊為total = N-1,每連線兩個不在同一集合中的頂點時,所需要的邊數減一(--total),ok了,最後連完之後的total就是還需要的邊數(也是現在的等價類數目),這個應該也很好理解。
程式實現:
#include <stdio.h>
int total;
int pre[1001];
void init(int n){
int i;
for(i=1;i<=n;++i){
pre[i] = i;
}
}
int root(int x){
if(x!=pre[x]){
pre[x] = root(pre[x]);
}
return pre[x];
}
void merge(int a,int b){
int x = root(a);
int y = root(b);
if(x!=y){
pre[x]=y;
--total;
}
}
int main(){
int N,M,i,st,end;
while(scanf("%d",&N) && N){
scanf("%d",&M);
init(N);
total = N-1;
for(i=0;i<M;++i){
scanf("%d %d",&st,&end);
merge(st,end);
}
printf("%d\n",total);
}
return 0;
}
這段程式碼就很好理解了。到此結束了。
相關文章
- 並查集應用並查集
- 並查集的應用2並查集
- 並查集深度應用並查集
- 並查集的簡單應用並查集
- 並查集(二)並查集的演算法應用案例上並查集演算法
- 並查集擴充套件應用並查集套件
- 並查集經典應用場景並查集
- 【學習筆記】並查集應用筆記並查集
- 【帶權並查集】理論和應用並查集
- 並查集在實際問題中的應用並查集
- 【並查集】【帶偏移的並查集】食物鏈並查集
- 並查集到帶權並查集並查集
- 並查集(一)並查集的幾種實現並查集
- 並查集的使用並查集
- 查並集
- 並查集演算法Union-Find的思想、實現以及應用並查集演算法
- 並查集(小白)並查集
- [leetcode] 並查集(Ⅱ)LeetCode並查集
- [leetcode] 並查集(Ⅲ)LeetCode並查集
- [leetcode] 並查集(Ⅰ)LeetCode並查集
- 3.1並查集並查集
- 寫模板, 並查集。並查集
- 並查集跳躍並查集
- 各種並查集並查集
- 淺談並查集並查集
- 食物鏈(並查集)並查集
- 並查集(Union Find)並查集
- The Door Problem 並查集並查集
- 並查集練習並查集
- 簡單易懂的並查集演算法以及並查集實戰演練並查集演算法
- BZOJ 4195 程式自動分析【並查集+離散化】並查集
- Soso 的並查集寫掛了並查集
- 【並查集】【離散化】[NOI2015] 程式自動分析並查集
- 並查集題目合集並查集
- 並查集java實現並查集Java
- 【轉】種類並查集並查集
- The Suspects-並查集(4)並查集
- 並查集擴充套件並查集套件
- (Day3)並查集並查集