1. 程式人生 > >codevs 1069 關押罪犯 並查集

codevs 1069 關押罪犯 並查集

技術分享 int == isp sin log 是把 pri turn

很有意思的一道題。剛開始看不出這是道並查集,後來看了題解才會做,就是把要分開的囚犯放在同個集合裏,表示這兩個囚犯不在同一間監獄,但不是直接合並,例如1和2要分開,則1和2’、1’和2合並(x’為x的虛點),同個集合中實點和虛點分屬於兩間監獄(即x’與y在不同監獄);再例如,1和2,2和3要分開,則1和2’合並,2’和3合並,那麽1和3會在同一間監獄,1’和2合並,2和3’合並,那麽2就在另一間監獄。這樣一來整道題的思路就呼之欲出了:按仇恨值從大到小分開每對囚犯,若出現無法分開的情況(即已在同一個監獄),則返回這對仇恨值並退出。附上AC代碼:

技術分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #define maxn 233333
 5 using namespace std;
 6 struct node{
 7     int a,b,c;
 8 };
 9 node e[maxn];
10 int N,M,fa[maxn];
11 int read();
12 bool cmp(node,node);
13 int getf(int);
14 int main(){
15 N=read();M=read(); 16 for(int i=1;i<=N*2;i++)fa[i]=i; 17 for(int i=1;i<=M;i++)e[i].a=read(),e[i].b=read(),e[i].c=read(); 18 sort(e+1,e+M+1,cmp); 19 for(int i=1;i<=M;i++){ 20 int t1=getf(e[i].a),t2=getf(e[i].b); 21 if(t1==t2){ 22 printf("
%d",e[i].c); 23 return 0; 24 } 25 fa[t1]=getf(e[i].b+N); 26 fa[t2]=getf(e[i].a+N); 27 } 28 putchar(0); 29 return 0; 30 } 31 int read(){ 32 int ans=0,f=1;char c=getchar(); 33 while(0>c||c>9){if(c==-)f=-1;c=getchar();} 34 while(0<=c&&c<=9)ans=ans*10+c-48,c=getchar();return ans*f; 35 } 36 bool cmp(node x,node y){ 37 return x.c>y.c; 38 } 39 int getf(int x){ 40 return fa[x]==x?x:getf(fa[x]); 41 }
並查集(補集的運用)

這道題中的並查集運用了補集的思想(在同一範圍內,x的補集為w,y的補集為w,那麽x和y會在同一個集合之中),有趣。

codevs 1069 關押罪犯 並查集