并查集
幷查集是一種很diao的數據結構,應用的很典型的栗子就是找共同的祖先,或者說是一組數字指向同一個根,是一種樹形的結構;
具體可以看一下這裡:別人家的博客
比如,給出幾個數,作為同學的編號,他們的初始父親是一個叫-1的節點:
-1 -1 -1 -1
1 2 3 4
如果他們有著同樣的興趣愛好,那麼就可以把它們合併到同一個父親節點上,比如合併到1:
1 1 1 1
1 2 3 4
這樣就形成了一個樹形的結構
1
2 3 4
本來1234是四個人的,現在變成了同一個興趣小組,所以幷查集可以看作是一個合併的過程,下面看他的具體應用:
只要理解上面的就沒有問題!
poj 2524. Ubiquitous Religions
1 // poj 2524. Ubiquitous Religions 2 // 并查集 求最多有多少个祖先 3 // references: 4 // no 5 #include <iostream> 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 10 using namespace std; 11 12 int p[50005]; 13 int ans; 14 15 void init() 16 { 17 memset(p, -1, sizeof(p)); 18 } 19 20 int find(int x) 21 { 22 return p[x] == -1 ? x : p[x] = find(p[x]); 23 } 24 25 void union_set(int u, int v) 26 { 27 int x = find(u); 28 int y = find(v); 29 if(x != y) 30 { 31 p[x] = y; 32 ans--; 33 } 34 } 35 36 int main() 37 { 38 int n, m, k = 1; 39 while(scanf("%d%d", &n, &m) != EOF, n, m) 40 { 41 ans = n; 42 init(); 43 int u, v; 44 for(int i=0; i<m; i++) 45 { 46 scanf("%d%d", &u, &v); 47 union_set(u, v); 48 } 49 printf("Case %d: %d\n", k++, ans); 50 } 51 return 0; 52 }
1 // poj 1611.The Suspects 2 // 并查集 3 // references: 4 // no 5 #include <iostream> 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 10 using namespace std; 11 12 const int N = 30005; 13 int n, m; 14 int p[N]; 15 int num[N]; 16 17 void init() 18 { 19 for(int i=0; i<n; i++) 20 { 21 p[i] = -1; 22 num[i] = 1; //记录该点为祖先的后代个数 23 } 24 } 25 26 int find(int x) 27 { 28 return p[x] == -1 ? x : p[x] = find(p[x]); 29 } 30 31 void union_set(int u, int v) 32 { 33 int x = find(u); 34 int y = find(v); 35 if(x != y) 36 { 37 p[x] = y; 38 num[y] += num[x]; //注意这里是加上x的num[],不只是++; 39 } 40 } 41 42 int main() 43 { 44 while(scanf("%d%d", &n, &m) != EOF, n) 45 { 46 init(); 47 for(int i=0; i<m; i++) 48 { 49 int k, u, v; 50 scanf("%d", &k); 51 scanf("%d", &u); 52 for(int j=1; j<k; j++) 53 { 54 scanf("%d", &v); 55 union_set(u, v); //都跟第一个合并 56 //u = v; 57 } 58 } 59 int x = find(0); //找到0的祖先 60 printf("%d\n", num[x]); 61 } 62 return 0; 63 }