看到題解大部分都是用『遞迴+路徑壓縮』做的,所以本蒟蒻就來發一篇『迴圈+路徑壓縮版並查集』的題解。速度比遞迴版本更加優秀(其實迴圈**還要好寫一些)。
並查集的操作有三步,初始化查詢祖先與合併。
既然並查集是來查詢祖先的,那麼初始化就必然是讓每個點的祖先指向自己
for(int i=1;i<=n;++i) fa[i]=i;
查詢操作就是不斷地向上走,直到找到祖先為止
while(x!=fa[x]) x=fa[x];
合併操作就是把乙個節點的祖先變為另乙個節點的祖先。
fa[find(a)]=find(b);//其中find(x)為x的祖先
並查集的單次查詢理想複雜度應該是o(logn)的,但是如果有乙個這樣的資料,並查集的複雜度就是o(n)了
為了避免這種情況,我們需對路徑進行壓縮。
即當我們經過找到祖先節點後,回溯的時候順便將它的子孫節點都直接指向祖先,使以後的查詢複雜度變回o(logn)甚至更低,讓圖變成這樣:
聽上去十分高階,實際上只要把剛剛的查詢操作變成如下就可以了
while(x!=fa[x]) x=fa[x]=fa[fa[x]];
並查集有兩個操作,既然查詢可以優化,那合併可不可以呢?
我們可以進行按秩合併,即:合併的時候將元素少的集合合併到元素多的集合中,這樣樹高會小很多
附上**:
#include using namespace std;
int n,m,z,x,y,fa[10005];//fa[i]是第i號節點的祖先
inline int find(int x)
//迴圈版找爹函式
/*//再附上遞迴版本的找爹函式
inline int find(int x)
*/int main()
while(m--)
if(z==2)
else } }
return 0;
}
並查集詳解
其實並查集顧名思義就是有 合併集合 和 查詢集合 兩種操作的關於資料結構的一種演算法。並查集演算法不支援分割乙個集合。用集合中的某個元素來代表這個集合,該元素稱為集合的代表元。乙個集合內的所有元素組織成以代表元為根的樹形結構。對於每乙個元素 parent x 指向x在樹形結構上的父親節點。如果x是根...
詳解並查集
並查集主要用來求解不相交集合的問題,主要針對於合併和查詢兩種演算法。並查集的實現主要包含了三個部分 並查集的初始化是對單個資料建立了乙個單獨的集合,每個集合應該包含以下兩個資料 由以上兩個資料,一般的並查集的結構一般有兩種表示形式 結構體構造如下 define max 50 struct node ...
並查集詳解
看大佬的形象解釋 並查集 按我現在對這個的理解 就是給你一堆數,然後給你兩個兩個數的關係,然後關係的傳遞性 連帶性 這些數就都有了關係 有關係的數組成乙個陣列,然後輸出這個一維陣列,裡面有幾個沒關係的陣列 應該怎麼做呢?第一種解釋是 每給兩個數就把乙個數當成祖宗,把另乙個數當成孩子,然後給了孩子和另...