洛谷P1525 关押罪犯 【思维 + 二分图判定】

传送门
题意: 给出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);
}

你可能感兴趣的:(二分图)