(并查集)P1525 关押罪犯
题意:有n个罪犯,给出m个三元组(a,b,w)表示罪犯a和b有仇恨关系,仇恨度为w,如果a和b关在同一个监狱就会爆发冲突。将所有罪犯划分到两个监狱,使最大的冲突最小,求出这个最小值。
题解:如果第a和b是敌人,那么 a 和 b的敌人 就是 朋友,可以被划分到同一集合。
按边权从大到小枚举,即优先把冲突大的分到两个集合中,直到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 }

浙公网安备 33010602011771号