並查集路徑壓縮 力扣547 並查集及其回滾

2021-10-12 04:39:40 字數 2034 閱讀 2225

547. 朋友圈

班上有 n 名學生。其中有些人是朋友,有些則不是。他們的友誼具有是傳遞性。如果已知 a 是 b 的朋友,b 是 c 的朋友,那麼我們可以認為 a 也是 c 的朋友。所謂的朋友圈,是指所有朋友的集合。

給定乙個 n * n 的矩陣 m,表示班級中學生之間的朋友關係。如果m[i][j] = 1,表示已知第 i 個和 j 個學生互為朋友關係,否則為不知道。你必須輸出所有學生中的已知的朋友圈總數。

示例 1:

輸入:

[[1,1,0],

[1,1,0],

[0,0,1]]

輸出: 2

第2個學生自己在乙個朋友圈。所以返回2。

示例 2:

輸入:

[[1,1,0],

[1,1,1],

[0,1,1]]

輸出: 1

1. n 在[1,200]的範圍內。

2. 對於所有學生,有m[i][i] = 1。

3. 如果有m[i][j] = 1,則有m[j][i] = 1。

即求鄰接矩陣中的連通分量數。完全照搬並查集模板,背譜就可以。

並查集支援兩個操作,same(x,y) 和 union(x,y)

same(x, y): 問 x 和 y 是否屬於同乙個集合

union(x, y): 將 x 和 y 所屬的集合合併成同乙個集合

兩個操作都要用到乙個內部操作, find(x)

find(x): 問 x 屬於那個集合,返回集合id
這些組成各個集合的元素以森林的形式維護,每棵樹代表乙個集合,同乙個集合的元素在同乙個樹上,每棵樹的根是集合的id。find(x) 操作需要從 x 節點向上找父節點直到樹根,樹根的編號就x所屬集合的id。這裡需要維護乙個 father 陣列,儲存 x 的父節點用於從 x 向上找根。

兩個優化

路徑壓縮:每次 find(x) 時,向上查詢過程中會經過一些節點,把這些節點的父節點都設為 find(x) 找到的根,以後的查詢再經過這個點的時候就可以一次找到根。

按秩合併:額外維護乙個 rank 陣列,rank[x] 表示以 x 為根的子樹的高度,合併時把較矮的樹的樹根連線到較高的樹的樹根上。

主要解決的問題:

加邊連通性:不斷加邊,同時問某兩個點是否連通

連通分量個數:本題就是

kruskal 最小生成樹

主要流程:建圖(本題輸入就是鄰接矩陣) -> 確定建並查集之後要算的值(本題是集合個數, **中的set_size) -> 根據圖建立並查集(merge) -> 返回要算的結果

class unionfindset 

~unionfindset(){}

bool same(int x, int y)

void merge(int x, int y)

--_set_size;

}int set_size()

private:

vector_father;

vector_rank;

int _set_size;

int _find(int x)

};class solution

};

如果並查集要支援回滾操作,就是要把已經合併成一棵樹的若干子樹,恢復成此前的若干子樹。需要開棧儲存每次合併操作時,被合併的哪乙個根(高度較小的那乙個根)。後續通過棧裡的資訊回滾。

支援回滾操作就不能使用路徑壓縮了。

stackst; // 儲存每次合併操作時被合併的根

void merge(int x, int y)

else

--_set_size;

}

並查集路徑壓縮 並查集 UnionFind 入門

咳咳,剛看完海賊更新,馬上呼哧呼哧寫下這篇文章,這週的目標就是出一篇並查集相關的文章,真的是時間咻咻一下就沒了。本文閱讀大概需要3分鐘。好了,並查集呢,英文叫union find 並查集是一種樹型的資料結構,通常來用於處理一些不相交集合的合併 union 問題,以及查詢 find 問題。如下 1 有...

並查集 壓縮路徑

並查集 union findsets 一種簡單的用途廣泛的集合.並查集是若干個不相交集合,能夠實現較快的合併和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數等。最完美的應用當屬 實現kruskar演算法求最小生成樹。並查集的精髓 即它的三種操作,結合實現 模板進行理解 1 make s...

並查集路徑壓縮

使用並查集查詢時,如果查詢次數很多,那麼使用樸素版的查詢方式肯定要超時。比如,有一百萬個元素,每次都從第一百萬個開始找,這樣一次運算就是10 6,如果程式要求查詢個一千萬次,這樣下來就是10 13,肯定要出問題的。這是樸素查詢的 適合資料量不大的情況 int findx int x 下面是採用路徑壓...