1. 程式人生 > >數據結構 並查集

數據結構 並查集

一個 efault mar left pts turn 一個數 baseline 數組

並查集是一種數據結構,字面意思上來說,就是一個支持合並和查詢的集合。

並查集

並查集的建立

1 void init()
2 {
3     for (int i = 1; i <= n; i++)
4     {
5         father[i] = i;
6     }
7 }

建立一個並查集很簡單,只要開一個數組。這個數組儲存某個節點對應的父節點編號。初始化時,將所有節點的父節點設為自己。

並查集的查找

 1 int get(int x)
 2 {
 3     // 如果當前節點的父節點就是自己,那麽說明這個節點是其所在集合的根節點。
 4     if (father[x] == x)
5 { 6 return x; 7 // 返回當前節點 8 } 9 // 否則遞歸查找該節點的父節點 10 return get(father[x]); 11 }

並查集的合並

 1 void merge(int x, int y)
 2 {
 3     // 分別找到連個節點的根節點
 4     x = get(x);
 5     y = get(y);
 6     if (x != y)
 7     // 如果兩個節點的根節點不是一個節點,那麽意味這它們不在一個集合當中
 8     // 此時就可以進行合並操作
 9     //
合並操作就是將其中一個節點所在集合的根節點的父親設為另外一個節點的根節點 10 { 11 father[y] = x; 12 } 13 }

路徑壓縮

在最壞情況下,樹是一條鏈,那麽它的查找時間復雜度會達到 O(n),這時我們所不希望看到的。

解決方法是:因為我們不關心這個樹的結構而是關心它的節點所在集合的關系,我們可以把一個集合裏的所有非根節點的父親節點都設為集合的根節點。

要做的只是在查找的代碼中稍微改動一下:

1 int get(int x)
2 {
3     if (father[x] == x)
4     {
5         return x; 
6 } 7 return father[x] = get(father[x]); 8 // 返回時將當前節點的父節點設為根節點 9 }

簡單例題

在社交的過程中,通過朋友,也能認識新的朋友。在某個朋友關系圖中,假定 A 和 B 是朋友,B 和 C 是朋友,那麽 A 和 C 也會成為朋友。即,我們規定朋友的朋友也是朋友。

現在,已知若幹對朋友關系,詢問某兩個人是不是朋友。

請編寫一個程序來解決這個問題吧。

輸入格式

第一行:三個整數 n,m,p(n≤5000,m≤5000,p≤5000),分別表示有 n 個人,m 個朋友關系,詢問 p 對朋友關系。

接下來 m 行:每行兩個數 Ai,Bi?i??,B?i??,1≤Ai,Bi≤N1\leq A_i,B_i\leq N1A?i??,B?i??N,表示 AiA_iA?i?? 和 BiB_iB?i?? 具有朋友關系。

接下來 p 行:每行兩個數,詢問兩人是否為朋友。

輸出格式

輸出共 p 行,每行一個YesNo。表示第 i 個詢問的答案為是否朋友。

樣例輸入

6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6

樣例輸出

Yes
Yes
No
 1 #include <iostream>
 2 using namespace std;
 3 int father[5000+1],n,m,p;
 4 void init()
 5 {
 6     for (int i = 1; i <= n; i++)
 7     {
 8         father[i] = i;
 9     }
10 }
11 int get(int x)
12 {
13     if (father[x] == x)
14     {
15         return x; 
16     }
17     return father[x] = get(father[x]);
18 }
19 void merge(int x, int y)
20 {
21     x = get(x);
22     y = get(y);
23     if (x != y)
24     {
25         father[y] = x;
26     }
27 }
28 int main()
29 {
30     memset(father,0,sizeof(father));
31     cin >> n >> m >> p;
32     init();
33     for (int i = 1; i <= m; i++)
34     {
35         int a,b;
36         cin >> a >> b;
37         merge(a,b);
38     }
39     for (int i = 1; i <= p; i++)
40     {
41         int a,b;
42         if (get(a) == get(b))
43             cout << "Yes" << endl;
44         else
45             cout << "No" << endl;
46     }
47     return 0;
48 }

非常簡單,只要把之前的幾個函數塞進去,一邊輸入一邊合並,最後查找就可以了。

數據結構 並查集