传送门
题意: 给出m对憎恨关系, 有一个憎恨值, 现在要将这n个人分成两堆人, 要求这两堆人中存在的憎恨值最大的最小, 问这个值是多少.
思路: 这种问题首先是二分, 然后我们如何check这个答案, 我们将所有边的憎恨值大于我们这个答案的新建一幅图, 然后我们判断能否避免掉这幅图的每一个边的关系, 怎么做了才能避免了? 实际上就是有憎恨关系的两个人一定要放在不同的集合中, 然后怎么判断不能放在同一个集合中了? 实际上就是判断一下当前这幅图是不是二分图就行了. 所以就是二分答案 + 判断是否是二分图
AC Code
const int maxn = 2e4 + 5;
const int maxm = 1e5 + 5;
struct node {
int to, next;
}e[2*maxm];
struct edge {
int u, v, w;
}s[maxm];
int cnt, head[maxn];
void add(int u, int v) {
e[cnt] = node{v, head[u]};
head[u] = cnt++;
}
int color[maxn]; bool flag;
void dfs(int u, int fa, int col) {
if (!flag) return ;
if (!color[u]) color[u] = col;
else if (color[u] != col) {
flag = false;
return ;
}
else return;
for (int i = head[u] ; ~i ; i = e[i].next) {
int to = e[i].to;
if (to == fa) continue;
dfs(to, u, 3-col);
}
}
int n, m;
bool ok(int x) {
cnt = 0; Fill(head, -1);
for (int i = 1 ; i <= m ; i ++) {
if (s[i].w > x) {
add(s[i].u, s[i].v);
add(s[i].v, s[i].u);
}
}
flag = true; Fill(color, 0);
for (int i = 1 ; i <= n ; i ++) {
if (!color[i]) dfs(i, -1, 1);
}
return flag;
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1 ; i <= m ; i ++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
s[i].u = u; s[i].v = v; s[i].w = w;
}
int l = 0, r = 1e9 +1, mid, ans;
while(r >= l) {
mid = (r + l) >> 1;
if (ok(mid)) {
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n", ans);
}