【POJ2112】Optimal Milking

Optimal Milking
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 16058 Accepted: 5749
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

题目大意:

描述:现在有C头奶牛要去K个挤奶点去挤奶,每一个挤奶点只能挤M头奶牛,现在给你K,C,M,和以邻接矩阵表示的K+C个物品(将   挤奶点和奶牛都看作物品)的两两距离。

问:如何安排使得在任何一头奶牛都有自己产奶机的条件下,奶牛到产奶机的最大距离最小?最小是多少?


这道题首先要满足每头奶牛都要挤到奶,即用最大流,新建一个超级源点和超级汇点,将每头奶牛当做边上的流,

于是每只奶牛与源点连边,容量为1,表示只能通过一只奶牛,每个挤奶机与汇点连边,容量为M,表示能通过M头奶牛。

那奶牛和挤奶机如何连边呢?题目要求我们找到最大距离的最小值,我们不妨先求出每个点之间的最小距离,然后二分答案,将当前答案作为距离上限,若奶牛和挤奶机的距离满足上限,就连边,容量为1。图建好后,跑最大流即可。

如果最大流小于C,就说明有奶牛没有挤奶,就扩大距离上限,反之则减小。


注意:奶牛和源点、挤奶机连边时容量必须是1。

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;

#define MAXN 230
#define MAXC 200
#define MAXM 15
#define MAXK 30
#define INF 0x3f3f3f3f
typedef long long int LL;

int K,C,M,N;
int map[MAXN+5][MAXN+5];
int G[MAXN+5][MAXN+5];
int d[MAXN+5],vd[MAXN+5];
int S,E;

void Floyd(int &Mindist,int &Maxdist)
{
    for(int k=1;k<=N;++k)
        for(int i=1;i<=N;++i)
            if(i!=k)for(int j=1;j<=N;++j)
                if(i!=j&&j!=k)
                    map[i][j]=min(map[i][j],map[i][k]+map[k][j]);

    for(int i=K+1;i<=N;++i)
        for(int j=1;j<=K;++j)
        {
            Mindist=min(Mindist,map[i][j]);
            Maxdist=max(Maxdist,map[i][j]);
        }
}

int aug(int u,int augco)
{
    if(u==E)return augco;

    int Dmin=N-1,augc=augco,delta;
    for(int v=1;v<=N;++v)
    {
        if(G[u][v]>0)
        {
            if(d[u]==d[v]+1)
            {
                delta=min(augc,G[u][v]);
                delta=aug(v,delta);

                G[u][v]-=delta;
                G[v][u]+=delta;
                augc-=delta;

                if(d[S]>=N)
                    return augco-augc;
                if(augc==0)
                    break;
            }

            Dmin=min(Dmin,d[v]);
        }
    }

    if(augco==augc)
    {
        --vd[d[u]];
        if(vd[d[u]]==0)
            d[S]=N;

        d[u]=Dmin+1;
        ++vd[d[u]];
    }

    return augco-augc;
}

int Sap(int Maxdist)
{
    memset(G,0,sizeof(G));

    for(int i=1;i<=K;++i)
        G[i][E]=M;
    for(int i=1;i<=C;++i)
        G[S][K+i]=1;

    for(int i=1;i<=K;++i)
        for(int j=1;j<=C;++j)
            if(map[K+j][i]<=Maxdist)
                G[K+j][i]=1;

    memset(vd,0,sizeof(vd));
    memset(d,0,sizeof(d));

    vd[0]=N;
    int flow=0;
    while(d[S]<N)
        flow+=aug(S,INF);
    return flow;
}

int main()
{
    scanf("%d%d%d",&K,&C,&M);
    int i,j;

    memset(map,0x3f,sizeof(map));
    N=K+C;
    S=N+1,E=N+2;

    for(i=1;i<=N;++i)
        for(j=1;j<=N;++j)
        {
             scanf("%d",&map[i][j]);
             if(i!=j&&!map[i][j])map[i][j]=INF;
        }


    int Mindist=INF,Maxdist=-INF;
    Floyd(Mindist,Maxdist);

    N+=2;
    int Middist;
    while(Mindist<Maxdist)
    {
        Middist=(Mindist+Maxdist)>>1;

        if(Sap(Middist)==C)Maxdist=Middist;
        else Mindist=Middist+1;
    }

    printf("%d\n",Mindist);
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值