並查集 帶權並查集詳解

2021-10-10 16:19:08 字數 1381 閱讀 5141

contents:

一.引入

二.查詢函式與集合合併函式(偽**)

三.權值如何更新

從圖的角度理解:

並查集實際上是一顆由若干個樹構成的森林,而如果還需要儲存邊的權值,則需要額外用乙個陣列d記錄每個結點和其父節點的權值

從集合的角度理解:

並查集儲存的資訊是某點屬於哪個集合,而帶權並查集還能記錄某點和其父結點的「關係」

這個思路其實很簡單,但是路徑壓縮函式和集合合併函式都需要改寫:

①因為路徑壓縮會改變點與點的連線關係,路徑壓縮後,點的父節點變為了根節點,所以需要更新d陣列

②集合的代表元(根節點)是沒有父結點的,所以d陣列中也沒有值。但是合併集合後其中乙個根節點變為了另乙個集合根節點的子節點,所以需要賦值

查詢函式:

int root_find(int x)
說明一下遞迴函式的邏輯:

它會先執行root_find()函式直至找到根節點,再回來執行當前函式中剩餘沒執行完的部分

也就是在你更新d[x]值時,d[pre[x]]是已經更新完了的

集合合併函式:

根節點是不儲存權值的,因為根節點沒有父節點,而在樹的合併時,其中乙個樹的根節點會變為另乙個樹的子結點,所以也需要為其賦上權值

void join(int x,int y)

}

上面的函式都是用偽**寫的,因為更新權值的規則要視題目而定

這個權值其實描述的是一種「關係」

以poj-1182這道很經典的食物鏈為例,題目規定三種物種:a**,b吃c,c吃a

可以用0表示和父結點同類,1表示吃父結點,2表示被父結點吃

則在更新權值時,可以這麼寫:

int root_find(int x)
前面說過,因為遞迴函式的特性,所以: ①rela[pre[x]]必然已經被更新為pre[x]到根節點的權值了

②而rela[x]存放的是x到pre[x]的權值

根據這兩段已知的關係(權值)我們可以推斷出x與根節點的關係

因為這道題三者迴圈的克制關係,可以使用模運算進行操作

集合合併會更複雜些,是由三對已知的關係推第四個已知關係:

即已知點x和rx的關係,點y和ry的關係,點x和點y的關係,推導點rx和點ry的關係

void join(int x,int y,int r)

}

具體的權值更新方式還是得看題目,但是原理大致就是如此了

並查集,帶權並查集

題意 ignatius過生日,客人來到,他想知道他需要準備多少張桌子。然而一張桌子上面只能坐上相互熟悉的人,其中熟悉可定義成為a與b認識,b與c認識,我們就說a,b,c相互熟悉 例如a與b熟悉and b與c熟悉,d與e熟悉,此時至少需要兩張桌子。輸入 t表示樣例個數,n表示朋友個數,朋友從1到n編號...

並查集和帶權並查集

並查集是乙個很高效演算法,理解起來也很簡單,寫起來更簡單。fat i i 找到乙個點的祖先 int findfat int x 二中的方法肯定不好,因為如果資料比較極端,那麼並查集就退化成乙個鏈了 如果加入了路徑壓縮,並查集這個演算法就更高效了。int findfat int x 遞迴寫法 int ...

並查集與帶權並查集

1.找點的祖先 fa i i 並查集的快主要在於路徑壓縮。1 遞迴寫法 int find int x 2 非遞迴寫法 int find int x return r 2.合併 合併2者的集合。void merge int x,int y 3.帶權並查集 一般是存下一些2者之間的具體的數量關係或者是統...