一道比较简单的并查集题,我们先把所有冲突事件按照影响力排序,之后从大到小处理他们。每次对于两个敌人,如果其中一个人没有敌人,那么就把他的敌人设为当前这个人,否则把他的敌人所在的集合与这个人合并即可。判断的时候如果两人在同一集合即不合法。
此题还有一种做法。我们要求的是最大值最小,所以我们还是很容易想到二分答案,之后我们就把问题转化成了判定性问题。怎么判定呢?因为如果要是满足条件的话,每对罪犯必然属于两个不同的监狱,也就是属于两个集合,他们其实构成了一个二分图。我们只要二分当前的值x,之后在跑图的时候,把图中所有小于x的边去掉,然后我们用常用的二分图判定染色法即可。
不过这个题我每次二分的好像有点问题……答案总是比标准情况多1,所以我选择了减1,不过要特判答案是0的情况。而且二分图的还比并查集稍微慢那么一点……
并查集代码:

#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') #define pr pair<int,int> #define mp make_pair #define fi first #define sc second using namespace std; typedef long long ll; const int M = 100005; const int N = 10000005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >='0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct fight { int x,y,z; bool operator < (const fight &g) const { return z > g.z; } }f[M]; int n,m,fa[M],e[M]; int getfa(int x) { return (x == fa[x]) ? x : fa[x] = getfa(fa[x]); } void merge(int x,int y) { int r1 = getfa(x),r2 = getfa(y); fa[r2] = r1; } bool pd(int x,int y) { int r1 = getfa(x),r2 = getfa(y); return (r1 == r2) ? 1 : 0; } int main() { n = read(),m = read(); rep(i,1,n) fa[i] = i; rep(i,1,m) f[i].x = read(),f[i].y = read(),f[i].z = read(); sort(f+1,f+1+m); rep(i,1,m+1) { if(pd(f[i].x,f[i].y)) printf("%d ",f[i].z),exit(0); if(!e[f[i].x]) e[f[i].x] = f[i].y; else merge(e[f[i].x],f[i].y); if(!e[f[i].y]) e[f[i].y] = f[i].x; else merge(e[f[i].y],f[i].x); } return 0; }
二分图代码:

#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') #define pr pair<int,int> #define mp make_pair #define fi first #define sc second using namespace std; typedef long long ll; const int M = 100005; const int N = 10000005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >='0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,v; }e[M<<1]; int n,m,x,y,z,maxx,ecnt,head[M],L,R,ans,col[M]; void add(int x,int y,int z) { e[++ecnt].to = y; e[ecnt].next = head[x]; e[ecnt].v = z; head[x] = ecnt; } bool pd(int x) { memset(col,0,sizeof(col)); queue <int> q; while(!q.empty()) q.pop(); rep(j,1,n) { if(col[j]) continue; q.push(j),col[j] = 1; while(!q.empty()) { int k = q.front();q.pop(); for(int i = head[k];i;i = e[i].next) { int t = e[i].to; if(e[i].v < x) continue; if(!col[t]) { col[t] = (col[k] == 1) ? 2 : 1; q.push(t); } else if(col[t] == col[k]) return 0; } } } return 1; } int main() { n = read(),m = read(); rep(i,1,m) x = read(),y = read(),z = read(),add(x,y,z),add(y,x,z),maxx = max(maxx,z); L = 0,R = maxx+1; while(L <= R) { int mid = (L+R) >> 1; //printf("#%d ",mid); if(pd(mid)) ans = mid,R = mid-1; else L = mid + 1; } if(!ans) printf("0 "); else printf("%d ",ans - 1); return 0; }