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;
}

 

posted @ 2012-12-10 21:13  yefeng1627  阅读(160)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor