演算法學習 連通性問題 並集查詢演算法

2021-08-13 22:20:05 字數 3160 閱讀 9282

連通性問題:

假如已知乙個整數對序列,每個整數代表某種型別的乙個物件,並且將p-q對解釋為p與q連通。假定連通可傳遞:如果p與q連通,q與r連通,那麼p與r連通。編寫乙個程式,從集合中過濾額外的連線對,如果前面的對表明p與q連通,則程式應該忽略p-q,並繼續輸入下乙個對。

例如 :

- input   output

- 3-4 3-4

- 4-9 4-9

- 8-0 8-0

- 2-3 2-3

- 5-6 5-6

- 2-9 (put out nothing because 2-3-4-9)

- 5-9 5-9

我們可以先將問題圖形化表示,先看乙個樹狀圖。(《algorithms in c》)

快速查詢(慢速並集)的思路很簡單:只要兩個陣列有相同的元素出現,那麼就可以認為這兩個陣列連通,可以把它歸併到一起,如上圖所示。

如果用**實現歸併呢?很簡單,只需要乙個陣列id,如果p與q連通,那麼讓id[p] = id[q],當且僅當id[p] == id[q]的時候,p與q連通。

#include

#define n 1000

//quick-find

int main()

while(scanf("%d %d",&p,&q) == 2)

t = id[p];

for(i = 0;i < n;i ++)

} printf("%d %d\n",p,q);}}

性質:對於具有n個物件,每個物件包括m個並集運算的連通性問題,快速查詢的演算法至少要執行mn條指令。

方案一中的查詢每一次都遍歷了陣列id的全部,效率要低很多,方案二提供了乙個更好的思路。

圖中表述的連通分量叫做樹,每棵樹只有乙個指向它本身的物件,即樹根,其餘的物件均指向或者間接指向樹根。比如一棵樹的根是9,那麼id[9] == 9,如果3->4,4->9,即id[3] == 4,id[4] == 9,3和4均不指向它本身,最終的指向都為9,3和4都在以9為根節點的書裡面。

這樣我們只需要找到樹的乙個節點,就可以根據這個節點找到樹根,從而判斷是否具有連通性了。

#include

#define n 1000

//quick-union

int main()

/*p q 0 1 2 3 4 5 6 7 8 9

3 4 0 1 2 4 4 5 6 7 8 9

4 9 0 1 2 4 9 5 6 7 8 9

8 0 0 1 2 4 9 5 6 7 0 9

2 3 0 1 9 4 9 5 6 7 0 9

5 6 0 1 9 4 9 6 6 7 0 9

2 9 0 1 9 4 9 6 6 7 0 9

5 9 0 1 9 4 9 6 6 7 0 9

*/while(scanf("%d %d",&p,&q) == 2)

id[i] = j; //p和q的樹根不相同,則把q的樹根賦給p的樹根,那麼這兩棵數就建立了聯絡變成了一棵樹

printf("%d %d\n",p,q); }}

性質:若m>n,快速並集演算法可能要執行多於m*n/2條指令來解決乙個擁有n個物件、m個對的連通性問題。

有了以上兩個演算法做鋪墊,加權快速演算法也就不難理解了,加權快速演算法是快速並集演算法的修改版:不是任意連通第二棵樹和第一棵樹,而是比較兩棵樹節點數多少,把小的樹的根節點連到大的樹的根節點上。這樣每個節點與樹根的距離短,查詢的運算效率也就高了。

**如下:

#include

#define n 1000

//weighted quick-union

int main()

while(scanf("%d %d",&p,&q) == 2)

if(size[i] < size[j])

else

printf("%d %d\n",p,q);}}

性質:加權快速並集演算法判斷n個物件的其中兩個是否連通,最多要跟蹤2*lgn個指標。

加權快速並集演算法最壞的情況是,每個並集運算連線相等大小樹。如果物件的數量小於2^n,則從任意節點到樹根的距離小於n。

現在我們發現,我們的演算法已經優化了很多,我們來討論這樣乙個問題:能否有乙個確保線性效能的演算法?

理想情況下,我們希望每乙個節點都直接指向根節點,而不希望付出變換大量指標的代價。其實這個很容易實現,我們可以通過修改樹的結構來達到這樣的目的。這種方法叫做路徑壓縮(path compression)。

實現方法是新增另一遍次經過每條路徑,把每個路徑id設定為指向根。最終結果是我們會看到乙個扁平的樹,接近快速查詢演算法的理想情況。

**如下:

#include

#define n 1000

//weighted quick-union with path compression by halving

int main()

while(scanf("%d %d",&p,&q) == 2)

for(j = q;id[j] != j;j = id[j])

if(i == j)

if(size[i] < size[j])

else

printf("%d %d\n",p,q);}}

《演算法》筆記 2 動態連通性問題

在基礎部分的最後一節,作者用乙個現實中應用非常廣泛的案例,說明以下幾點 動態連通性問題的輸入是一列整數對,其中的每個整數都表示乙個某種型別的物件,一對整數對p q可以理解為 p和q是相連的 相連是一種等價關係,其具有 程式的目標是過濾掉序列中無意義的整數對,當程式從輸入中讀取了整數對pq時,如果已知...

並查集 解決連通性問題

給的輸入形式不同,但都是利用並查集,並查集的實現是不變的。1 323.無向圖中連通分量的數目 給定編號從 0 到 n 1 的 n 個節點和乙個無向邊列表 每條邊都是一對節點 請編寫乙個函式來計算無向圖中連通分量的數目。2 547.省份數量 連通分量的數目 有 n 個城市,其中一些彼此相連,另一些沒有...

Sicily 連通性問題 演算法逐層優化

description 關係r具有對稱性和傳遞性。數對p q表示prq,p和q是0或自然數,p不等於q。要求寫乙個程式將數對序列進行過濾,如果乙個數對可以通過前面數對的傳遞性得到,則將其濾去。例如 輸入 輸出 連通性 3 4 3 4 4 9 4 9 8 0 8 0 2 3 2 3 5 6 5 6 2...