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

题目链接: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 }
原文地址:https://www.cnblogs.com/Leohh/p/7637800.html