帶權並查集 學習乙個

2021-08-01 14:29:55 字數 2740 閱讀 2006

(生活有點小煩,希望在寫**的時候能夠純粹一點。)

先作一點鋪墊:

從以前的認識來看,並查集(union-find sets)可以實現分類的目的。

她提供兩種操作:1.find-查詢根節點   2.union-合併(兩個元素間的關係將兩個不同集合合併為乙個,保證了關係的傳遞性)

值得注意的是並查集有兩個優化的方法——

1. 為了防止退化成鏈,合併兩個集合時,將高度小的的樹接在高度高的樹上。(卡這一點的題目我還沒有遇到過...)

2. 重要的是路徑壓縮;我用的模版裡,在查詢的時候進行了路徑壓縮——將根節點到查詢節點整條鏈上的結點都接到根節點上(因為是遞迴,所以是從根節點開始壓縮路徑的

(因為合併在查詢之後,再怎樣防止退化都不能阻止高度增加。)

(#事實上這種寫法在壓縮路徑前任何么蛾子結構都可能出現,資料結構的並查集應該時時保證結構高度只有兩層吧?)

int find(int i)

void unin(int a,int b)

現在每個節點只有乙個屬性——f[i],代表的是他的父親結點,我們每次壓縮路徑(更改父節點)就是在維護f[i]的值指向集合的根節點。

帶權並查集就是在每個節點定義權值v[i],這個值代表的是和父節點的關係。

並在1.查詢(壓縮路徑)和2.合併 的時候維護這個值。//根據題意寫更新的算式

此時,同一集合不代表同一種類,而是維護了元素間的關係。

換句話說,在同一集合的兩結點,他們的關係就是已知的(根據權值判斷是否錯誤);如果不在同一集合,那就更新關係(預設正確)。

(並查集通過合併的方法來區別不同的集合,帶權並查集是一種思路,種類並查集是另一種思路)

然後現在只有乙個問題,就是我如何找出乙個集合中任意兩點之間的關係(畢竟每個節點只存有和父親節點的關係)——利用路徑壓縮,兩個節點會被接到同乙個根節點上(此時權值也已經更新為和根節點的關係);這樣兩個節點之間只有乙個(或者沒有)中間節點,很容易推出需要查詢的兩結點間的關係。

以下是兩道練習題:

poj1182 食物鏈

題意:動物分成三類abc,相互的關係是a吃b,b吃c,c吃a的迴圈關係;

n個動物,m次詢問。 

「r a b」為一次詢問,r==1時ab為同類動物,r==2a吃b

1.a、b大於n 或者 2.自己吃自己 或者 3.和已知關係衝突的詢問 是錯誤詢問,最後輸出錯誤詢問次數。

思考:把所有關係都存起來,還能根據傳遞性推出任意兩點間的關係,這就是關係並查集啊。需要構造的是一種迴圈吃的三元關係,毛估估想一下,已知兩個節點對同一節點的關係是可以推出這兩個節點的關係的(那就可以用帶權並查集)。定義權值為「被父節點吃-2,吃父節點-1,和父節點同類-0」

之前說要在1.查詢(壓縮路徑)和2.合併 的時候維護權值,很重要的是——我要在三層結構中完成對權值的維護。(為什麼要在三層結構進行維護呢,因為查詢的時候壓縮路徑是從根節點開始壓縮的)就是說,已知和父親的權值和父親對爺爺的權值,將我現在對父親的權值更新為我對爺爺的權值,因為我壓縮路徑直接接到爺爺結點了。我是列舉了各種情況湊出了乙個更新權值的公式——v[i]=(v[i]+v[f[i]])%3;  

所以,查詢(壓縮路徑)實現如下:

int find(int i)

return f[i];

}

判斷權值是否副符合:自己推公式吧,反正壓縮路徑之後就是兩層的結構。

還有值得一提的是——合併操作:因為路徑壓縮後只有兩層結構:a-->ta    b-->tb兩棵樹,要將ta接到tb上步驟是:求出ta對a的權值,ta接到b上,再接到tb上:

v[ta]=( ( (3-v[a])%3 + (r-1) )%3 +v[b] )%3;

ac**:

#include #include #define maxn 50005

using namespace std;

int n,k;

int r,a,b;

int ans;

int f[maxn],v[maxn];

void init(int n)

}int find(int i)

return f[i];

}void merge(int a,int b)

else

}int main()

cout<

shuoj 1880

題意:武林中共有n 個人,編號分別為1~n,有m條命令,兩種格式:

1 x y:編號為x和y的兩個人所在的幫派合併了,x 的幫派的幫主歸於y 的門下,y 的等級比x 的幫派的幫主高一級(如果x 和y 已經在乙個幫派中,則跳過這條命令。);

2 x y:請回答編號為x和y的兩個人是否是自己人。

思路:權值為和父親的等級差距

ac**:

#include #include #define maxn 100005

using namespace std;

int n,m;

int r,x,y;

int ans;

int f[maxn],v[maxn];

void init(int n)

}int find(int i)

return f[i];}

int main()

else if(r==2)

}return 0;

}

以上,帶權並查集入門吧。

今天icpc world final

並查集,帶權並查集

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

帶權並查集

食物鏈 time limit 1000ms memory limit 10000k total submissions 71395 accepted 21146 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n...

帶權並查集 then

問題 b 便 時間限制 2 sec 記憶體限制 512 mb 提交 50 解決 14 題目描述 給出乙個r c的棋盤.共有r行c列,r c個格仔.現要在每個格仔都填乙個非負整數.使得任意乙個2 2的正方形區域都滿足這樣的性質 左上角的數字 右下角的數字 左下角的數字 右上角的數字.有些格仔已經確定,...