並查集和帶權並查集

2021-10-02 03:19:22 字數 2621 閱讀 5069

簡介

並查集是一種以陣列為儲存結構的樹形資料結構,當其中一些元素發生從屬關係時,我們把可以關聯的元素看做乙個個的集合(即a連線b,c也連線b,那麼a,b,c可以看做乙個集合)

基本操作

初始化

首先定義乙個father陣列,初始化就是令陣列中每個人的父親都是他自己,即f[i]暫時表示i的父親。當出現這種情況時,它就是這一脈的祖宗

for

(int i=

1;i<=n;i++

) father[i]

=i;

建立關係建立關係的步驟就是對於每給出的一對數x和y,我們都假設成x是y的祖先(或者都假設成y都是x的祖先)

father[y]

=x;

然後這樣就能連成樹狀結構

但是這樣還不行,當我想找兩個數是否是不是同一祖先,我必須順著樹形結構依次摸到公共祖先(摸的方法是遞迴查詢,當且僅當乙個數的祖先是它的本身返回給該值),顯然時間是不夠的,比如下面的函式就是求乙個數x的最大祖先

int

find

(int x)

因此我們引入路徑壓縮的概念:假如6已經是4的祖先,那麼我們新增乙個關係是"4 7",則我們,可以直接在遞迴查詢的過程中,將7的father直接設為6,這樣可以避免鏈狀樹形結構的出現而直接形成最多深度為2的樹。

find函式

int

find

(int x)

//或者寫成最簡短的形式

intfind

(int x)

union函式如果我們需要把x和y兩個不同的集合連線,顯然需要找出他們的fx和fy,然後將fx連向fy或者fy連向fx都可

void

union

(int x,

int y)

}

計算集合的個數不管是實際生活還是做題,使用並查集計算某個群體中集合的個數是並查集最直接的應用,在上面我們聯合函式的基礎上,我們是否能通過集合去重實現求集合個數呢?答案是否定的,有的同學會想,我們不是把所有有聯絡的群體都設定為公共的祖先了嗎?

在union函式的過程中,當要出現大於等於三個人的關係時,find函式就可以輕鬆將第三層關係轉化到第二層的關係上,但是可能其他的二層關係並沒有接入到該集合的公共祖先上,主要是操作的先後順序影響

方法一:不管上述瑕疵直接求

int ans=0;

for(

int i=

1;i<=num;i++)if

(father[i]

==i) ans++

;

int ans=0;

for(

int i=

1;i<=num;i++

)find

(i);

for(

int i=

1;i<=num;i++)if

(father[i]

==i) ans++

;

帶權並查集

想必學過資料結構(或者離散數學)的人都知道一種特殊的圖叫做帶權圖,當然也有帶權的樹。因此我們就不難明白帶權並查集是什麼了。我們在維護集合的聯絡關係時,還要維護乙個可以用值表現的關係(如對立,距離等),下面我們都用乙個陣列value表示這種權值關係,注意每次value陣列要清零,可以和father陣列的初始化一起進行

有了上面並查集的基礎,廢話不多說,直接解釋find函式和union函式:

find函式

顯然當出現新的聯絡時,我們在考慮路徑壓縮的同時,還應儲存下來這次father查到的數(假設與x不相同),使value加上到祖先上的value之和

int

find

(int a)

union函式當出現新的聯絡時,如下圖的兩個集合,我們需要如果我們要把y的集合連向x的集合,顯然需要father[fy] = fx;

接下來value的變化和我們連線祖先節點應該照應。帶權並查集根本上是帶權有向圖,這裡的指向關係是一種向量關係。因此我們更新value[fy],並且從fy指向fx的權值應該是通過y與x的關係倒著求出來(注意向量的求和)

如果是x集合連向y集合就反過來

void

union

(int x,

int y,

int s)

}

並查集和帶權並查集

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

並查集,帶權並查集

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

並查集與帶權並查集

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者之間的具體的數量關係或者是統...