(并查集)P1525 关押罪犯

题意:有n个罪犯,给出m个三元组(a,b,w)表示罪犯a和b有仇恨关系,仇恨度为w,如果a和b关在同一个监狱就会爆发冲突。将所有罪犯划分到两个监狱,使最大的冲突最小,求出这个最小值。

 

题解:如果第a和b是敌人,那么 ab的敌人 就是 朋友,可以被划分到同一集合。

按边权从大到小枚举,即优先把冲突大的分到两个集合中,直到a和b已经在同一集合中,输出此时的边权。

 

上述算法非常直观,正确性却不是很显然。

考虑如果最终答案是wi,那么大于wi的边权必然连接不同的集合,因此答案是满足单调性的。

Code:
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 
 5 struct Edge{
 6     ll a,b,w;
 7 }e[1000006];
 8 ll n,m,fa[1000006],enemy[1000006];
 9 
10 bool cmp(Edge a,Edge b){return a.w>b.w;}
11 int find(ll x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
12 int uni(ll x,ll y){fa[find(x)]=find(y);}
13 bool check(ll x,ll y){return find(x)==find(y);}
14 
15 int main(){
16   scanf("%lld%lld",&n,&m);
17   for(int i=1;i<=n;++i)fa[i]=i;
18   for(int i=1;i<=m;++i){
19       scanf("%lld%lld%lld",&e[i].a,&e[i].b,&e[i].w);
20     }
21     
22     sort(e+1,e+1+m,cmp);
23     
24     for(int i=1;i<=m;++i){
25         int x=e[i].a,y=e[i].b;
26         if(check(x,y)){
27             printf("%lld",e[i].w);
28             return 0;
29         }
30         if(!enemy[x]) enemy[x]=y;
31           else uni(enemy[x],y);
32         if(!enemy[y]) enemy[y]=x;
33           else uni(enemy[y],x);
34     }
35     printf("0"); 
36 }
View Code

 

 

 

 
posted @ 2020-02-11 23:56  _vv123  阅读(48)  评论(0)    收藏  举报