BZOJ 1529 [POI2005]ska Piggy banks:並查集

Leohh發表於2017-10-08

題目連結:http://www.lydsy.com/JudgeOnline/problem.php?id=1529

題意:

  Byteazar有N個小豬存錢罐。

  每個存錢罐只能用鑰匙開啟或者砸開。

  Byteazar已經把每個存錢罐的鑰匙放到了某些存錢罐裡。

  Byteazar 現在想買一臺汽車於是要把所有的錢都取出來。

  他想盡量少的打破存錢罐取出所有的錢,問最少要打破多少個存錢罐。

 

題解:

  並查集。

  

  如果開啟a的鑰匙放在b中,那麼如果開啟了b,a也能開啟。

  所以將a的認爹箭頭指向b。

  

  對於一個集合,只要開啟了這個集合的老大,那麼其他的就都能開啟。

  所以答案為集合個數。也就是統計find(i) == i的點的個數。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 1000005
 5 
 6 using namespace std;
 7 
 8 int n;
 9 int ans=0;
10 int par[MAX_N];
11 
12 void init_union_find()
13 {
14     for(int i=1;i<=n;i++)
15     {
16         par[i]=i;
17     }
18 }
19 
20 int find(int x)
21 {
22     return par[x]==x?x:par[x]=find(par[x]);
23 }
24 
25 void unite(int x,int y)
26 {
27     int px=find(x);
28     int py=find(y);
29     if(px==py) return;
30     par[px]=py;
31 }
32 
33 bool same(int x,int y)
34 {
35     return find(x)==find(y);
36 }
37 
38 void read()
39 {
40     cin>>n;
41     init_union_find();
42     int a;
43     for(int i=1;i<=n;i++)
44     {
45         cin>>a;
46         unite(i,a);
47     }
48 }
49 
50 void solve()
51 {
52     for(int i=1;i<=n;i++)
53     {
54         if(find(i)==i) ans++;
55     }
56 }
57 
58 void print()
59 {
60     cout<<ans<<endl;
61 }
62 
63 int main()
64 {
65     read();
66     solve();
67     print();
68 }

 

相關文章