poj 2112 最大流+二分+floyd

/*
题意:k台机器和c头牛分别在自己的点,输入为路径,c头牛要到k台机器挤奶,每台机器最多挤m头牛,求最短
的最远行走距离。

题解:最大流+二分+floyd;
题目求的是每次行走路程中每头牛行走的最远距离,因此直接在最开始的时候用floyd求出从一个点到另一个点
的最短距离,这样就保证了牛走的都是最短距离,然后根据求出的最短路径来建图,并且用二分的方法把大于值
mid的边全部去掉后,判断是否能求出最大流使得所有牛都被挤过一次,源点为0,连接每台机器,权值为m,每
头牛连接汇点k+c+1,权值为1。
*/
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

#define EMAX 15000
#define VMAX 400

const int INF = 0xfffffff;

int pre[VMAX];
int map[VMAX][VMAX],nmap[VMAX][VMAX];

void floyd(int n)
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            if (INF != map[j][i])
                for(int k=1; k<=n; k++)
                    if (map[j][i] + map[i][k] < map[j][k])
                        map[j][k] = map[j][i] + map[i][k];
}

void build(int k, int c, int m, int val)
{
    memset(nmap,0,sizeof(nmap));
    for(int i=1; i<=k; i++)
        nmap[0][i] = m;
    for(int i=1; i<=c; i++)
        nmap[k+i][k+c+1] = 1;
    for(int i=1; i<=k; i++)
        for(int j=1; j<=c; j++)
            if (map[i][k+j] <= val)
                nmap[i][k+j] = 1;
}

int flow_ek(int s, int t, int n)
{
    queue<int> Q;
    int ret = 0;
    while (true)
    {
        memset(pre,-1,sizeof(pre));
        while (!Q.empty())
            Q.pop();
        Q.push(s);
        while (!Q.empty())//BFS
        {
            int u = Q.front();
            Q.pop();
            for(int v=1; v<=n; v++)
            {
                if (nmap[u][v] && pre[v] == -1)
                {
                    pre[v] = u;
                    Q.push(v);
                }
            }
            if (pre[t] != -1)//终点的pre不为-1,表示找到一条增广路径
                break;
        }
        if (pre[t] == -1)//当BFS后找不到增广路径则结束循环
            break;
        int mw = -1;
        for(int v=t; v!=s; v=pre[v])//找出当前路径中的流量的最小容量
        {
            if (mw == -1 || mw > nmap[pre[v]][v])
                mw = nmap[pre[v]][v];
        }
        for(int v=t; v!=s; v=pre[v])//修改路径的容量,求出残余网络
        {
            nmap[pre[v]][v] -= mw;
            nmap[v][pre[v]] += mw;//更新逆向边
        }
        ret += mw;
    }
    return ret;
}

int bin(int k, int c, int m, int n)//二分
{
    int left = 0, right = 40000,mid;
    while (left < right)
    {
        mid = (left+right)/2;
        build(k,c,m,mid);
        if (c == flow_ek(0,k+c+1,n))
            right = mid;
        else
            left = mid+1;
    }
    return right;
}


int main(void)
{
    int k,c,m;
    while (cin >> k >> c >> m)
    {
        for(int i=1; i<=k+c; i++)
            for(int j=1; j<=k+c; j++)
            {
                cin >> map[i][j];
                if (i != j && 0==map[i][j])
                    map[i][j] = INF;
            }
        floyd(k+c);
        cout << bin(k,c,m,k+c+2) << endl;
    }
    return 0;
}

 

posted @ 2014-03-20 23:51  辛力啤  阅读(191)  评论(0编辑  收藏  举报