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 }