一道比较简单的并查集题,我们先把所有冲突事件按照影响力排序,之后从大到小处理他们。每次对于两个敌人,如果其中一个人没有敌人,那么就把他的敌人设为当前这个人,否则把他的敌人所在的集合与这个人合并即可。判断的时候如果两人在同一集合即不合法。
此题还有一种做法。我们要求的是最大值最小,所以我们还是很容易想到二分答案,之后我们就把问题转化成了判定性问题。怎么判定呢?因为如果要是满足条件的话,每对罪犯必然属于两个不同的监狱,也就是属于两个集合,他们其实构成了一个二分图。我们只要二分当前的值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('\n') #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\n",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; }