「POI2010」Bridges

传送门
Luogu团队题链接

解题思路

首先二分答案,然后在所有边权小于二分值的边和所有点组成的图中判欧拉回路。
由于可能出现混合图,所以要用到网络流。
把所有无向边钦定一个方向,那么原图就是一个有向图。
那么存在欧拉回路的充要条件就所有点的入度等于出度且图联通。
我们考虑把点 \(x\) 的入度与出度之差记作 \(\Delta x\)
那么对于所有的定向后的无向边 \((u,v)\),连一条从 \(u\rightarrow v\) 的容量为 \(1\) 的边。
表示将该条边反向可以使 \(\Delta u += 2,\Delta v -= 2\)
然后考虑对于所有度数差小于 \(0\) 的点 \(x\),连一条 \(s \rightarrow x\) 的容量为 \(\frac{|\Delta x|}{2}\) 的边。
表示 \(x\) 需要操作这么多次,使得 \(\Delta x\) 达到 \(0\)。小于零的情况同理。
最后判断是否满流即可。

细节注意事项

  • 细节有点多,要有耐心

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <queue>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

const int _ = 1010;
const int __ = 5010 * 2 + 1010 * 2;
const int INF = 2147483647;

int tot = 1, head[_], nxt[__], ver[__], cap[__];
inline void Add_edge(int u, int v, int d)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, cap[tot] = d; }
inline void link(int u, int v, int d) { Add_edge(u, v, d), Add_edge(v, u, 0); }

int n, m, s, t, liu, dgr[_], dep[_];
struct node{ int a, b, c, d; }g[__];

inline int bfs() {
    static queue < int > Q;
    memset(dep, 0, sizeof dep);
    dep[s] = 1, Q.push(s);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        for (rg int i = head[u]; i; i = nxt[i]) {
            int v = ver[i];
            if (dep[v] == 0 && cap[i] > 0)
                dep[v] = dep[u] + 1, Q.push(v);
        }
    }
    return dep[t] > 0;
}

inline int dfs(int u, int flow) {
    if (u == t) return flow;
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i];
        if (dep[v] == dep[u] + 1 && cap[i] > 0) {
            int res = dfs(v, min(flow, cap[i]));
            if (res) { cap[i] -= res, cap[i ^ 1] += res; return res; }
        }
    }
    return 0;
}

inline int Dinic() {
    int res = 0;
    while (bfs()) while (int d = dfs(s, INF)) res += d;
    return res;
}

inline bool check(int mid) {
    s = 0, t = n + 1;
    tot = 1, memset(head, 0, sizeof head);
    for (rg int i = 1; i <= m; ++i) {
        if (g[i].c > mid) return 0;
        if (g[i].d <= mid) link(g[i].a, g[i].b, 1);
    }
    for (rg int i = 1; i <= n; ++i) {
        if (dgr[i] < 0) link(s, i, -dgr[i] / 2);
        if (dgr[i] > 0) link(i, t, dgr[i] / 2);
    }
    return Dinic() == liu / 2;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
#endif
    read(n), read(m);
    for (rg int i = 1; i <= m; ++i) {
        read(g[i].a), read(g[i].b), read(g[i].c), read(g[i].d);
        if (g[i].c > g[i].d)
            swap(g[i].a, g[i].b), swap(g[i].c, g[i].d);
        --dgr[g[i].a], ++dgr[g[i].b];
    }
    for (rg int i = 1; i <= n; ++i) {
        if (dgr[i] % 2 != 0) return puts("NIE"), 0;
        liu += abs(dgr[i]) / 2;
    }
    int l = 1, r = 1000;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    printf("%d\n", l);
    return 0;
}

完结撒花 \(qwq\)

猜你喜欢

转载自www.cnblogs.com/zsbzsb/p/11745810.html