zoukankan      html  css  js  c++  java
  • poj 2391 Ombrophobic Bovines 最短路 二分 最大流 拆点

    题目链接

    题意

    (n)个牛棚,每个牛棚初始有(a_i)头牛,最后能容纳(b_i)头牛。有(m)条道路,边权为走这段路所需花费的时间。问最少需要多少时间能让所有的牛都有牛棚可待?

    思路

    二分

    因为问题具有单调性,因此考虑二分时间,(check)是否满足条件。

    满足条件指什么呢?
    是指所有的牛都有牛棚可待。
    是指所有的牛都顺利地从某一个牛棚移动到了另一个合法的牛棚(或者不移动),而这个移动是在限定的时间范围内的。

    建图

    首先拆点,将牛棚拆成 初始牛棚 与 终态牛棚。

    1. 在 源点 到 初始牛棚 之间连边,权值为初始时该牛棚内牛的个数。

    2. 在 终态牛棚 到 汇点 之间连边,权值为该牛棚最终可容纳的牛的个数。

    3. 在 初始牛棚 到 终态牛棚 之间连边:
      ((u_i,v_j),(v_i,u_j)):当且仅当移动的时间(d(i,j))小于当前(check)的值时,才可以连这条边;
      ((u_i,u_i)):因为无需花费时间,所以永远可以连上。
      这两类边的权值都是(inf),因为只要在限定的时间范围内,任意多的牛都可以从上面通过。

    如果最大流对于源点而言是满流,则(check)成功

    总括

    综上所述,本题即最短路+二分+最大流

    Code

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #define inf1 0x3f3f3f3f3f3f3f3f
    #define inf2 0x3f3f3f3f
    #define maxn 1010
    #define maxm 200010
    using namespace std;
    typedef long long LL;
    LL a[maxn][maxn], mx, d;
    struct Edge { int to, ne, c; }edge[maxm];
    int dep[maxn], ne[maxn], tmp[maxn], n,m, tot, s,t,num, x[maxn], y[maxn];
    void add(int u, int v, int c) {
        edge[tot] = {v, ne[u], c};
        ne[u] = tot++;
        edge[tot] = {u, ne[v], 0};
        ne[v] = tot++;
    }
    int bfs(int src) {
        memset(dep, 0, sizeof dep);
        dep[src] = 1;
        queue<int> q;
        while (!q.empty()) q.pop();
        q.push(src);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int i = ne[u]; ~i; i = edge[i].ne) {
                int v = edge[i].to;
                if (edge[i].c > 0 && !dep[v]) dep[v] = dep[u] + 1, q.push(v);
            }
        }
        return dep[t];
    }
    int dfs(int u, int flow) {
        if (u == t) return flow;
        int ret = 0;
        for (int i = ne[u]; ~i; i = edge[i].ne) {
            int v = edge[i].to;
            if (edge[i].c > 0 && dep[v] == dep[u] + 1) {
                int c = dfs(v, min(flow-ret, edge[i].c));
                edge[i].c -= c;
                edge[i^1].c += c;
                ret += c;
                if (ret == flow) break;
            }
        }
        if (!flow) dep[u] = 0;
        return ret;
    }
    void floyd() {
        for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) a[i][j] = inf1;
        for (int i = 1; i <= n; ++i) a[i][i] = 0;
        while (m--) {
            int u, v;
            scanf("%d%d%lld", &u, &v, &d);
            a[u][v] = a[v][u] = min(a[u][v], d);
        }
        for (int k = 1; k <= n; ++k) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= n; ++j) {
                    if (k==i||k==j) continue;
                    a[i][j] = a[j][i] = a[i][k]+a[k][j] < a[i][j] ? a[i][k]+a[k][j] : a[i][j];
                }
            }
        }
        mx = 0;
        for (int i = 1; i <= n; ++i) for (int j = i+1; j <= n; ++j) if (a[i][j] != inf1) mx = max(mx, a[i][j]);
    }
    bool check(LL lim) {
        tot = 0; memset(ne, -1, sizeof ne);
        for (int i = 1; i <= n; ++i) {
            add(s, i, x[i]); add(n+i, t, y[i]);
            add(i, n+i, inf2);
        }
        int cnt = tot;
        for (int i = s; i <= t; ++i) tmp[i] = ne[i];
        for (int i = 1; i <= n; ++i) {
            for (int j = i+1; j <= n; ++j) {
                if (a[i][j] <= lim) add(i, n+j, inf2), add(j, n+i, inf2);
            }
        }
        int ans=0, ret=0;
        while (bfs(s)) {
            while (ret = dfs(s, inf2)) ans += ret;
        }
        return ans == num;
    }
    int main() {
        scanf("%d%d", &n, &m);
        s = 0, t = n<<1|1, num = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &x[i], &y[i]);
            num += x[i];
        }
        floyd();
        LL l = 0, r = mx;
        while (r > l) {
            LL mid = l+r>>1;
            if (check(mid)) r = mid;
            else l = mid+1;
        }
        if (check(l)) printf("%lld
    ", l);
        else puts("-1");
        return 0;
    }
    
    
  • 相关阅读:
    [模板]RMQ(冲刺准备中)
    洛谷 P2569[SCOI2010]股票交易(动规+单调队列)
    洛谷 P3659 [USACO17FEB]Why Did the Cow Cross the Road I G
    粗略了解fill与fill_n
    计蒜客D2T2 蒜头君的排序(动态维护树状数组)
    洛谷 P3478 [POI2008]STA-Station
    洛谷 P2899 [USACO08JAN]手机网络Cell Phone Network
    洛谷 P3112 [USACO14DEC]后卫马克Guard Mark
    洛谷 P3092 [USACO13NOV]没有找零No Change
    洛谷 P2850 [USACO06DEC]虫洞Wormholes 判负环
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/7778822.html
Copyright © 2011-2022 走看看