洛谷P1525 关押罪犯
题意:
告诉n个人,m对关系,每队关系价值C,通过分配n个人到两个监狱,来使得同一个监狱内的最高价值最小。
题解:
通过并查集维护一个分配。
怎么分配呢,从大到小排序价值,优先把较大的都分到不同监狱,直到出现第一个矛盾直接输出。
分到不同监狱=将敌人的敌人和自己分到一个监狱,但是敌人的敌人遍历容易超时,而且还要特殊记录。
前1~n和n+1~2n分别表示同一个监狱。a和b+n在同一个集合内表示的意思就是a和b不在一个监狱,a和b在一个集合内表示的意思是在一个监狱。通过前者这样的维护关系,可以极大地简化复杂度。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const int MAXN = 200010;
int n,m;
struct node{
int a,b;
int var;
}A[MAXN];
int cmp(node a,node b){
return a.var>b.var;
}
struct UnionSet {
int f[MAXN];
UnionSet(int n) {
for (int i = 1; i <= n; i++) {
f[i] = i;
}
}
UnionSet(){}
void uni(int x, int y) {
f[find(x)] = find(y);
}
bool query(int x, int y) {
return find(x) == find(y);
}
int find(int x) {
return f[x] == x ? x : (f[x] = find(f[x]));
}
} us;
int main(){
cin>>n>>m;
FOR(i,1,m){
int a,b,v;
scanf("%d%d%d",&a,&b,&v);
A[i].a=a,A[i].b=b,A[i].var=v;
}
us=UnionSet(2*n);
sort(A+1,A+1+m,cmp);
bool ok = false;
FOR(i,1,m){
if(us.query(A[i].a,A[i].b)||us.query(A[i].a+n,A[i].b+n)){
cout<<A[i].var<<endl;
ok = true;
break;
}
else{
us.uni(A[i].a,A[i].b+n);
us.uni(A[i].a+n,A[i].b);
}
}
if(!ok)puts("0");
}