codevs 1069 關押罪犯 並查集
阿新 • • 發佈:2017-08-18
技術分享 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 關押罪犯 並查集