紧跟着上一道乌龟棋就写了这个题,这道题当时是讲并查集的时候提到的,但是到目前为止蒟蒻还没有想明白怎么用并查集搞这道题,所以就写二分图的染色。
首先可以判断这道题的答案是满足单调性的,假设二分的答案是mid,那么大于mid的仇恨关系都不在同一监狱中,那么当二分的答案是mid+k时,大于mid+k的仇恨关系当然也是可以不在同一监狱中的。
所以可以使用二分,二分答案后如何判断当前答案是否可行,可以染色:对仇恨关系大于mid的边构成的图(注意,可能不是连通图)染色,染色成功则答案可行,失败则反之。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int n, m, e, l, r, mid;
short col[20001];
bool vis[20001];
vector <int> G[20001];
struct edge{
int v, w;
}E[200001];
bool dfs(int u){
for(int i = 0; i < G[u].size(); i++){
int v = E[G[u][i]].v, w = E[G[u][i]].w;
if(w > mid){
if(col[v] == col[u]) return 0;
if(vis[v]) continue;
col[v] = -col[u];
vis[v] = 1;
if(!dfs(v)) return 0;;
}
}
return 1;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++){
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
E[++e].v = v;
E[e].w = w;
G[u].push_back(e);
E[++e].v = u;
E[e].w = w;
G[v].push_back(e);
r = max(r, w);
}
while(l < r){
mid = (l+r)>>1;
memset(vis, 0, sizeof vis);
memset(col, 0, sizeof col);
bool flag = 0;
for(int i = 1; i <= e; i++){
if(!vis[E[i].v] && E[i].w > mid){
vis[E[i].v] = 1;
col[E[i].v] = 1;
if(dfs(E[i].v)) continue;
flag = 1; break;
}
}
if(flag) l = mid+1;
else r = mid;
}
printf("%d", l);
}