zoukankan      html  css  js  c++  java
  • POJ 2391.Ombrophobic Bovines (最大流)

    实际上是求最短的避雨时间。

    首先将每个点拆成两个,一个连接源点,一个连接汇点,连接源点的点的容量为当前单的奶牛数,连接汇点的点为能容纳的奶牛数。

    floyd求任意两点互相到达的最短时间,二分最长时间,最大流判断是否可行。

    注意路径时间会超过int

    /*
          最大流SAP
          邻接表
          思路:基本源于FF方法,给每个顶点设定层次标号,和允许弧。
          优化:
          1、当前弧优化(重要)。
          1、每找到以条增广路回退到断点(常数优化)。
          2、层次出现断层,无法得到新流(重要)。
          时间复杂度(m*n^2)
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ms(a,b) memset(a,b,sizeof a)
    using namespace std;
    const int INF = 500;
    long long G[INF][INF];
    struct node {
        int v, c, next;
    } edge[INF*INF * 4];
    long long  pHead[INF*INF], SS, ST, nCnt;
    void addEdge (int u, int v, int c) {
        edge[++nCnt].v = v; edge[nCnt].c = c, edge[nCnt].next = pHead[u]; pHead[u] = nCnt;
        edge[++nCnt].v = u; edge[nCnt].c = 0, edge[nCnt].next = pHead[v]; pHead[v] = nCnt;
    }
    int SAP (int pStart, int pEnd, int N) {
        int numh[INF], h[INF], curEdge[INF], pre[INF];
        int cur_flow, flow_ans = 0, u, neck, i, tmp;
        ms (h, 0); ms (numh, 0); ms (pre, -1);
        for (i = 0; i <= N; i++) curEdge[i] = pHead[i];
        numh[0] = N;
        u = pStart;
        while (h[pStart] <= N) {
            if (u == pEnd) {
                cur_flow = 1e9;
                for (i = pStart; i != pEnd; i = edge[curEdge[i]].v)
                    if (cur_flow > edge[curEdge[i]].c) neck = i, cur_flow = edge[curEdge[i]].c;
                for (i = pStart; i != pEnd; i = edge[curEdge[i]].v) {
                    tmp = curEdge[i];
                    edge[tmp].c -= cur_flow, edge[tmp ^ 1].c += cur_flow;
                }
                flow_ans += cur_flow;
                u = neck;
            }
            for ( i = curEdge[u]; i != 0; i = edge[i].next)
                if (edge[i].c && h[u] == h[edge[i].v] + 1)     break;
            if (i != 0) {
                curEdge[u] = i, pre[edge[i].v] = u;
                u = edge[i].v;
            }
            else {
                if (0 == --numh[h[u]]) continue;
                curEdge[u] = pHead[u];
                for (tmp = N, i = pHead[u]; i != 0; i = edge[i].next)
                    if (edge[i].c)  tmp = min (tmp, h[edge[i].v]);
                h[u] = tmp + 1;
                ++numh[h[u]];
                if (u != pStart) u = pre[u];
            }
        }
        return flow_ans;
    }
    long long m, n, x, y,sum,c;
    int in[INF], out[INF];
    bool check (long long tem) {
        nCnt = 1;
        SS = 2 * n + 1, ST = 2 * n + 2;
        memset (pHead, 0, sizeof pHead);
        for (int i = 1; i <= n; i++) {
            if(out[i]) addEdge (SS, i, out[i]);
            for (int j =1; j <= n; j++)
                if (G[i][j] <= tem&&G[i][j]!=-1)
                    addEdge (i, j+n, 5000);
        }
        for (int i = 1; i <= n; i++)
                  if(in[i])addEdge (i + n, ST, in[i]);
        int ans = SAP (SS, ST, ST);
        if (ans == sum) return 1;
        return 0;
    }
    int main() {
        /*
               建图,前向星存边,表头在pHead[],边计数 nCnt.
               SS,ST分别为源点和汇点
        */
        ms (G, -1);
        cin>>n>>m;
        for (int i = 1; i <= n; i++) {
            cin>>out[i]>>in[i];
            sum += out[i];
        }
        long long l = 0x7fffffffffffffff, r = 0;
        for (int i = 1; i <= n; i++) G[i][i] = 0;
        for (int i = 1; i <= m; i++) {
            cin>>x>>y>>c;
            if(G[x][y]>0) G[x][y] = G[y][x] = min(c,G[x][y]);
            else
                         G[x][y]=G[y][x]=c;
            l = min (l, c), r = max (r, c);
        }
        for (int  t = 1; t <= n; t++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++) {
                    if (G[i][t] == -1 || G[t][j] == -1) continue;
                    if (G[i][j] == -1 || G[i][j] > G[i][t] + G[t][j])
                        G[i][j] = G[i][t] + G[t][j], l = min (l, G[i][j]), r = max (r, G[i][j]);
                }
        long long last = -1,mid;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (check (mid) ) {
                last = mid;
                r = mid - 1;
            }
            else l = mid + 1;
        }
        cout<<last;
        return 0;
    }
    View Code
  • 相关阅读:
    国际标准:ISO 8601
    Python中文问题SyntaxError
    主人与狗
    三星Galaxy note I9220 N7000 刷机ROOT工具及ROM下载
    电子书下载:Pro ASP.NET 4 in C# 2010
    Rad Studio IDE 代码编辑器增强工具 RADSplit
    电子书下载:Essential Windows Phone 7.5
    3D成像法:抖动
    减小delphi生成EXE文件体积的方法
    unisynedit 在Delphi 2010下的编译问题
  • 原文地址:https://www.cnblogs.com/keam37/p/3973941.html
Copyright © 2011-2022 走看看