zoukankan      html  css  js  c++  java
  • poj 2112 Optimal Milking 最大流

    题目大意: 

      有K个挤奶器,C头奶牛,每个挤奶器最多能给M头奶牛挤奶。

    求使C头奶牛头奶牛需要走的路程的最大路程最小。

    解题思路: 

      使用Floy预先求出任意两点间最短距离,然后二分枚举最大距离.

      构图方案: 源点与奶牛连边,容量为1, 挤奶器与汇点连边,容量为M,  奶牛与挤奶器连边 (注意,这里只有单项边)

      还要注意的是,因为预先求过最短路,初始化的时候对于0的边,赋值的无穷大不要设的太大,不然会溢出.

    参考代码:

      SAP(shortest augment path)   间隙优化,  AC时间 110ms

      

    View Code
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    const int inf = 10000000;
    const int MAXN = 500;
    #define MIN(a,b) (a)<(b)?(a):(b)
    #define MAX(a,b) (a)>(b)?(a):(b)
    int k, c, m, s, t, n, N;
    int mp[MAXN][MAXN];
    int head[MAXN], idx, vh[MAXN], h[MAXN];
    struct node{
        int v, f, nxt;
    }edge[MAXN*MAXN];
    
    void input() {
        n = k+c; s = 0; t = n+1; N = n+2;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                scanf("%d", &mp[i][j] );
                if( !mp[i][j] ) mp[i][j] = inf;    
            }    
        for(int z = 1; z <= n; z++)    
            for(int i = 1; i <= n; i++)
                if( mp[i][z] != inf ) 
                {    
                    for(int j = 1; j <= n; j++)
                        if( mp[i][j] > mp[i][z]+mp[z][j] )
                            mp[i][j] = mp[i][z]+mp[z][j];
                }
    }
    void AddEdge( int u, int v, int f )
    {
        edge[idx].v = v; edge[idx].f = f;
        edge[idx].nxt = head[u]; head[u] = idx++;
        edge[idx].v = u; edge[idx].f = 0;
        edge[idx].nxt = head[v]; head[v] = idx++;
    }
    void build( int mid )
    {
        memset( head, 0xff, sizeof(head) ); idx = 0;
        for(int i = 1; i <= k; i++) // 挤奶器
            for(int j = k+1; j <= n; j++) //奶牛
            {
                if( mp[j][i] <= mid ) // 这里注意,只有奶牛到挤奶器的边
                    AddEdge( j, i, 1 );
            }
        for(int i = 1; i <= k; i++) //挤奶器与汇点连边
            AddEdge( i, t, m );
        for(int i = k+1; i <= n; i++) //奶牛与源点连边
            AddEdge( s, i, 1 );
    }
    int DFS(int u,int flow )
    {
        if( u == t ) return flow;
        int tmp = h[u]+1, remain = flow;
        for(int i = head[u]; ~i; i = edge[i].nxt )
        {
            int v = edge[i].v;
            if( edge[i].f && h[u] == h[v]+1 )
            {
                int p = DFS( v, MIN( remain, edge[i].f ));
                edge[i].f -= p; edge[i^1].f += p; remain -= p;
                if( remain == 0 || h[s] == N ) return flow-remain;
            }
        }
        for(int i = head[u]; ~i; i = edge[i].nxt )
            if( edge[i].f ) tmp = MIN( tmp, h[ edge[i].v ] );
        if( !( --vh[ h[u] ] ) ) h[s] = N;
        else    ++vh[ h[u] = tmp+1 ];
        return flow-remain;
    }
    int sap()
    {
        int maxflow = 0;
        memset( h, 0, sizeof(h));
        memset( vh, 0, sizeof(vh));
        vh[0] = N;
        while( h[s] < N ) maxflow += DFS( s, inf );
        return maxflow;
    }
    void solve()
    {
        int l = 0, r = 100000;
        while( r > l )
        {
            int mid = (l+r)>>1;
            build( mid );
            if( sap() >= c ) r = mid;
            else    l = mid+1;
        }
        printf("%d\n", r );
    }
    int main()
    {
        while( scanf("%d%d%d", &k,&c,&m ) != EOF)
        {
            input();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    Lyft Level 5 Challenge 2018
    Codeforces Round #514 (Div. 2)题解
    Bubble Cup 11
    不如来搞一下CDQ分治吧!
    Codeforces Round #331 (Div. 2)
    写一下中国剩余定理的证明
    codeforces Round#332Div2 题解
    GCPC2017 题解
    2017 USP Try-outs 题解
    CodeForce 387D. George and Interesting Graph
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2812001.html
Copyright © 2011-2022 走看看