並查集 最小生成樹詳細講解

2022-08-12 15:30:22 字數 3895 閱讀 9466

簡單來說,並查集的主要操作有:

1-合併兩個不相交的集合

2-查詢兩個元素是否屬於同乙個集合

nkoj 1205 親戚
或許你並不知道,你的某個朋友是你的親戚。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孫子。如果能得到完整的家譜,判斷兩個人是否親戚應該是可行的,但如果兩個人的最近公共祖先與他們相隔好幾代,使得家譜十分龐大,那麼檢驗親戚關係實非人力所能及。在這種情況下,最好的幫手就是計算機。

為了將問題簡化,你將得到一些親戚關係的資訊,如同marry和tom是親戚,tom和ben是親戚,等等。從這些資訊中,你可以推出marry和ben 是親戚。請寫乙個程式,對於我們的關於親戚關係的提問,以最快的速度給出答案。

輸入格式

輸入由兩部分組成。

第一部分以n,m開始。n為問題涉及的人的個數(1 ≤ n ≤ 20000)。這些人的

編號為1,2,3,…,n。下面有m行(1 ≤ m ≤ 100000),每行有兩個數ai, bi,表示已知ai和bi是親戚。

第二部分以q開始。以下q行有q個詢問(1 ≤ q ≤ 1 000 000),每行為ci,di,表示詢問ci和di是否為親戚。

輸出格式

對於每個詢問ci, di,若ci和di為親戚,則輸出yes,否則輸出no。

樣例輸入

10  7

2  4

5  7

1  3

8  9

1  2

5  6

2  3

33  4

7  10

8  9

樣例輸出

yesno

yes傳送門

從題目中我們可以得到一些提示,它就是要讓我們構建乙個關係集合出來,再快速查詢兩個元素是否位於同一集合,這顯然就與並查集的效用十分吻合。

基於此演算法如此高的時間複雜度,我們採用某種特殊的手段來優化它,這也便是並查集的核心內容——路徑壓縮

查詢同時路徑壓縮

int getfather(int v)   

}

合併兩個集合
void merge(int x, int y)
我們回到引例,我們現在可以很輕鬆地解決此題(偽**)——
for (i = 1; i <= n; ++ i)father[i] = i;	//初始化  

for (i = 1; i <= m; ++ i)

for (i = 1; i <= q; ++ i) (o(m))

#######提供幾道並查集的簡單練習:

nkoj 3197 島嶼

nkoj 1046 關押罪犯

簡言之,最小生成樹就是在乙個連通圖中生成一棵樹,剛好連通所有節點,所含邊數(或邊權總和最小)。

舉個栗子,感受一下——

引例:村長的難題

何老闆是某鄉村的村長,何老闆打算給該村的所有人家都連上網。

該村有n(1<=n<=1000)戶人家,編號1到n。由於地形等原因,只有

m(1<=m<=50000)對人家之間可以相互牽線。在不同人家間牽線的長度不一定相同。比如在ai與bi之間牽線需要ci公尺長的網線。

整個村的網路入口在1號人家,何老闆的問題是:是否能使得所有人家都連上網?使所有人家都連上網,最少需要多少公尺網線?

關注這個例子,我們的解法是要用網線連線n戶人家,找出一種方案,使得總的長度最少。我們目測可到樣圖的最小生成樹

接下來我會介紹三種演算法:

1-kruskal(克魯斯卡爾演算法)

2-prim(普里姆演算法)

3-boruvka演算法

這三種演算法都是基於貪心思想的應用,但其中kruskal可處理同權邊的情況,而boruvka不可以。

kruskal演算法的基本思想:

每次選不屬於同一生成樹的且權值最小的邊的頂點,將邊加入生成樹,並將所在的2個生成樹合併,直到只剩乙個生成樹。

排序使用quicksort

檢查是否在同一生成樹用並查集

總時間複雜度o(mlogm),其中m表示邊的數量

以下是用kruskal解決引例的**:
#define maxm 10003

#define maxn 103

struct node edge[maxm]; //邊的資訊

int n, m; //n為頂點數,m為邊數

int father[maxn]; //father存i的父親節點

bool cmp(node a, node b)

void ini()

int getfather(int x)

void kruskal()

} printf("%d", tot);

} int main()

prim演算法的基本思想:
任選乙個點,加入生成樹集合。

在未加入生成樹的點中,找出離生成樹距離最近的乙個點,將其加入生成樹。

反覆上述操作,直到所有點都加入了生成樹。

總時間複雜度o(n^2),其中n為點的個數

以下給出prim函式**:
void prim(int x) 

for (i = 1; i <= n - 1; ++ i)

dis[k] = 0;

for (j = 1; j <= n; ++ j)

if( dis[j] > map[j][k])

} }

並查集(最小生成樹)

時間限制 1000 ms 記憶體限制 65536 kb 題目描述 有一張城市地圖,圖中的頂點為城市,無向邊代表兩個城市間的連通關係,邊上的權為在這兩個城市之間修建高速公路的造價,研究後發現,這個地圖有乙個特點,即任一對城市都是連通的。現在的問題是,要修建若干高速公路把所有城市聯絡起來,問如何設計可使...

最小生成樹 並查集練習

叢林中的路 熱帶島嶼lagrishan的首領現在面臨乙個問題 幾年前,一批外援資金被用於維護村落之間的道路,但日益繁茂的叢林無情的侵蝕著村民的道路,導致道路維修開銷巨大,長老會不得不放棄部分道路的維護。已經知道了每條路每個月的維修費用 單位為aacms 現在長老會需要提出一種方案,即需要保證村落之間...

並查集 最小生成樹(prim kruskal)

並查集,從名字上來看可以知道,是乙個集合,而且這個集合可以合併和查詢。查詢,主要是查詢集合中的某乙個元素的祖先是誰,某一些元素是不是擁有相同的祖先。合併,是把兩個不想交的集合合併為乙個集合。並查集的思想就是朋友的朋友就是朋友 雖然現實生活中並不是這樣 並查集的第一步初始化,自己是自己的祖先。乙個人來...