[洛谷P1525] 关押罪犯

题目链接:

传送门

题目分析:

由最后划分的结果在两个集合,联想到二分图
又由于答案具有单调性,即如果当前答案可以则更大的答案也一定可以,想到二分答案
思路:
二分答案,每次对于答案进行检验,检验时将\(<=\)答案的边都忽略掉,只保留比答案大的边,然后进行染色判定二分图,如果能构成二分图,说明这些点可以被分在两个不同的集合,且由二分图的定义可以得到,集合内的点之间无连边,而两集合之间的连边在本题的背景下等于被断掉了,即可以保证有分配方案使得冲突值小于二分到的答案

代码:

#include<bits/stdc++.h>
#define N 50010
#define M 200010
using namespace std;
inline int read() {
    int cnt = 0, f = 1; char c;
    c = getchar();
    while (!isdigit(c)) {
        if (c == '-') f = -f;
        c = getchar();
    }
    while (isdigit(c)) {
        cnt = cnt * 10 + c - '0';
        c = getchar();
    }
    return cnt * f;
}
int first[N], nxt[M], to[M], w[M], tot, Max = -1, ans;
int color[N];
int n, m, x, y, z;
void add(int x, int y, int z) {
    nxt[++tot] = first[x];
    first[x] = tot;
    to[tot] = y;
    w[tot] = z;
}
bool Dfs (int u, int t) {
    for (register int i = first[u]; i; i = nxt[i]) {
        if (w[i] <= t) continue;
        int v = to[i];
        if (!color[v]) {
            color[v] = 3 - color[u];
            if(!Dfs(v, t)) return false;
        }
        else if (color[v] == color[u]) return false;
    }
    return true;
}
bool check (int res) {
    memset(color, 0, sizeof(color));
    bool flag = true;
    for (register int i = 1; i <= n; i++) {
        if (!color[i]) {
            color[i] = 1;
            if(!Dfs(i, res)) {
                flag = false;
                break;
            }
        }
    }
    return flag;
}
int solve(int r) {
    int l = 0;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}
int main() {
    n = read(); m = read();
    for (register int i = 1; i <= m; i++) {
        x = read(); y = read(); z = read();
        add(x, y, z);
        add(y, x, z);
        if (z > Max) Max = z;
    }
    ans = solve(Max);
    printf("%d", ans);
    return 0;
}

转载于:https://www.cnblogs.com/kma093/p/10807671.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值