POJ 2112 Optimal Milking (Dinic + 二分)

Optimal Milking
Time Limit: 2000MS   Memory Limit: 30000K
Total Submissions: 9498   Accepted: 3433
Case Time Limit: 1000MS

Description

FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C. 

Each milking point can "process" at most M (1 <= M <= 15) cows each day. 

Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine. 

Input

* Line 1: A single line with three space-separated integers: K, C, and M. 

* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line. 

Output

A single line with a single integer that is the minimum possible total distance for the furthest walking cow. 

Sample Input

2 3 2
0 3 2 1 1
3 0 3 2 0
2 3 0 1 0
1 2 1 0 2
1 0 0 2 0

Sample Output

2

Source

 
 
题意:有K台挤奶机、C头奶牛,以及他们之间距离,每只奶牛都要走到任意一台机器中,每台机器最多为M只奶牛服务,问所有奶牛都完成任务,所走的路程最远的那只奶牛,所走的路程最短可以是多少。

思路:floyd + 二分+ 最大流。
很容易想到最大流 建立一个超级源点和汇点把挤奶机和汇点连起来 容量为M ,奶牛与源点连起来 容量为1
先floyd求出每两个实体间的最小距离 然后二分找出最大
 

1)先用floyd求到任意milking machine到 任意奶牛之间距离

2)查找到最长的一条距离,并记录下来为max,那么我们就可以知道,要求的值就是在[0,max]区间

3)下面就开始二分查找了,找到0到max之间,最小的一个值X,使得这个值刚好能使二分图完成匹配

4)而使二分图能完成匹配的条件就是,使构造的网络流的最大流的值正好等于奶牛数

 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;

const int VM=300;
const int INF=0x3f3f3f3f;

int K,C,M;
int g[VM][VM],map[VM][VM],src,des;
int dep[VM];

void buildgraph(int x){
    memset(map,0,sizeof(map));
    for(int i=K+1;i<=K+C;i++)   //奶牛与源点相连,流量为1
        map[src][i]=1;
    for(int i=K+1;i<=K+C;i++)   //奶牛与能到达的机器(距离<x的点)相连,流量为1
        for(int j=1;j<=K;j++)
            if(g[i][j]<=x)
                map[i][j]=1;
    for(int i=1;i<=K;i++)   //机器与汇点相连,流量为 M
        map[i][des]=M;
}

int BFS(){
    queue<int> q;
    while(!q.empty())
        q.pop();
    memset(dep,-1,sizeof(dep));
    dep[src]=0;
    q.push(src);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int v=src;v<=des;v++)
            if(map[u][v]>0 && dep[v]==-1){
                dep[v]=dep[u]+1;
                q.push(v);
            }
    }
    return dep[des]!=-1;
}

int DFS(int u,int minx){
    if(u==des)
        return minx;
    int tmp;
    for(int v=src;v<=des;v++)
        if(map[u][v]>0 && dep[v]==dep[u]+1 && (tmp=DFS(v,min(minx,map[u][v])))){
            map[u][v]-=tmp;
            map[v][u]+=tmp;
            return tmp;
        }
    dep[u]=-1;
    return 0;
}

int Dinic(){
    int ans=0,tmp;
    while(BFS()){
        while(1){
            tmp=DFS(src,INF);
            if(tmp==0)
                break;
            ans+=tmp;
        }
    }
    return ans;
}

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d%d",&K,&C,&M)){
        src=0, des=K+C+1;
        int i,j,k;
        for(i=1;i<=K+C;i++)
            for(j=1;j<=K+C;j++){
                scanf("%d",&g[i][j]);
                if(g[i][j]==0)
                    g[i][j]=INF;
            }
        for(k=1;k<=K+C;k++)
            for(i=1;i<=K+C;i++)
                for(j=1;j<=K+C;j++)
                    if(g[i][j]>g[i][k]+g[k][j])
                        g[i][j]=g[i][k]+g[k][j];
        int l=0,r=-INF;
        for(i=1;i<=K;i++)
            for(j=K+1;j<=K+C;j++)
                if(g[i][j]!=INF && r<g[i][j])
                    r=g[i][j];
        //printf("r=%d\n",r);
        int ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            buildgraph(mid);
            int tmp=Dinic();
            //int tmp=EK();
            if(tmp>=C){
                ans=mid;
                r=mid-1;
            }else
                l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jackge/p/3053186.html