帶權並查集


  學習帶權並查集之前我們需要先對並查集和路徑壓縮壓縮了解,有需求的可以參考這篇博客

剛昨天總結了並查集的相關操作,今天做題的時候居然發現自己一直都是存在一些想不到的地方,總是會存在一些漏洞,最騷的是今天做到了食物鏈這道題......才知道了帶權並查集和種類並查集......好了接下

來就要進入帶權並查集了。

  上面的博客中有寫到路徑壓縮的相關操作,我們知道路徑壓縮的結果就是同一集合中的所有元素統一指向樹根,這樣可以加快訪問速度。和路徑壓縮一樣,帶權並查集僅僅是在每個集合元素都指向樹根

的前提下賦予這些結點相對於樹根的權值。

  那么我們就需要用一個數組一個元素相對於他所屬集合樹根的權值,我們用value存儲。

  我們已經知道了基本並查集的一般實現,但是如果加入了value要如何實現呢。

  

  我們思考:

    在find函數中,我們對於每個元素進行一次賦值,使得最終所有元素的父親結點都指向樹根結點,那么如果帶有權值的話,我們知道每次都會改變一個結點的父親,知道找到他所屬集合的樹根,所以

  我們每次也需要更新對應的value值。

    那么合並函數呢,我們知道每次合並我們會將x所屬集合的樹根px的父親設置為y所屬集合的樹根py,這樣就可以將兩個集合合並,那么我們知道在這過程中我們改變了px的父親,也就需要改變px對

應他父親的權值,我們根據下圖就可以知道,對於value[px],因為x最終父親為py,所以顯然兩條路的權值應該相等,我們就可以得出如下代碼。

    並不是所有類型的更新都是下面這種情況,具體情況具體分析,但是思路寶貴。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 const int maxn = 10000 + 5;
 6 int head[maxn], value[maxn], rank[maxn];
 7 
 8 int find(int u) {
 9     if(u != head[u]) {
10         int t = head[u];
11         head[u] = find(head[u]);
12         value[u] += value[t];
13     }
14     return head[u];
15 }
16 
17 void Union_Set(int x, int y, int s) {
18     int fx = find(x), fy = find(y);
19     if(fx == fy) return;
20     if(rank[fx] > rank[fy]) {
21         head[fy] = fx;
22         value[fy] = -value[y] + value[x] + s;
23     } else {
24         head[fx] = fy;
25         value[fx] = -value[x] + value[y] + s;
26         if(rank[fx] == rank[fy]) rank[fy] ++;
27     }
28 }
29 
30 int is_same(int x, int y) {
31     return find(x) == find(y);
32 }
33 
34 int main () {
35 
36     return 0;
37 }  

  后續會更新相關題目:針對題目再做詳細描述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM