poj 2112 Optimal Milking 解题报告

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

真是气......建图建反了还过了样例,改了好久好久才发现

题意如下:有一堆牛要到挤奶机那去,每个挤奶机只能安排m个牛去挤奶,现在问你怎么安排能让最慢到达挤奶机的奶牛尽快到达,

输入格式为: 挤奶机数量,奶牛数量,每台上限

接下来前k行为每个挤奶机到其他点的距离

后c行为每个奶牛到其他点的距离,0为这两点不可直接到达


思路如下:


先floyd求出来任意两点的最短路

二分枚举最远的那条路的长度,然后在保证所有的路都不长于枚举的值的情况下构图,看看有没有C头奶牛到达可以通过你构的图到达挤奶机,如果可以缩小你的枚举,否则扩大。

然后看看有没有C头奶牛可以通过你构的图到达挤奶机可以通过网络流实现。设置超级源点,到每个奶牛流量为1,设置超级汇点,每个挤奶机到汇点流量为m,然后看汇点总流量是否大于或等于c即可


代码如下:

#include <cstdio>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
#define inf 1000000007
using namespace std;
int k,c,m;
int dist[305][305];
int G[305][305],E,layer[305];
void init(){
    memset(dist,0,sizeof(dist));
    for(int i=1;i<=k+c;i++){
        for(int j=1;j<=k+c;j++){
            scanf("%d",&dist[i][j]);
            if(dist[i][j]==0)dist[i][j]=inf;
        }
    }
    for(int l=1;l<=k+c;l++){//floyd求最短路
        for(int i=1;i<=k+c;i++){
            for(int j=1;j<=k+c;j++){
                dist[i][j]=min(dist[i][j],dist[i][l]+dist[l][j]);
            }
        }
    }
}
void build(int mid){//构图
    memset(G,0,sizeof(G));
    for(int i=1;i<=k;i++)G[i][E]=m;
    for(int i=k+1;i<=k+c;i++)G[0][i]=1;
    for(int i=1;i<=k;i++){
        for(int j=k+1;j<=k+c;j++){
            if(dist[j][i]<=mid)G[j][i]=1;//注意这里是G[j][i]个dist[j][i],我就是这里写反了然后一直wa
        }
    }
}
bool find_layer(){
    memset(layer,-1,sizeof(layer));
    queue<int>q;
    while(!q.empty())q.pop();
    layer[0]=0;
    q.push(0);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=1;i<=E;i++){
            if(G[now][i] && layer[i]==-1){
                layer[i]=layer[now]+1;
                q.push(i);
                if(i==E)return true;
            }
        }
    }
    return false;
}
bool Dinic(int mid){
    build(mid);
    deque<int>dq;
    int vis[305];
    int ans=0;
    while(!dq.empty())dq.pop_front();
    while(find_layer()){
        memset(vis,0,sizeof(vis));
        vis[0]=1;
        dq.push_back(0);
        while(!dq.empty()){
            if(dq.back()==E){
                int Min=inf,Min_s;
                for(int i=1;i<dq.size();i++){
                    int s=dq[i-1],e=dq[i];
                    if(G[s][e]<Min){
                        Min=G[s][e];
                        Min_s=s;
                    }
                }
                ans+=Min;
                for(int i=1;i<dq.size();i++){
                    int s=dq[i-1],e=dq[i];
                    G[s][e]-=Min;
                    G[e][s]+=Min;
                }
                while(!dq.empty() && dq.back()!=Min_s){
                    vis[dq.back()]=0;
                    dq.pop_back();
                }
            }
            else {
                int flag=1;
                for(int i=1;i<=E;i++){
                    if(G[dq.back()][i] && !vis[i] && layer[i]==layer[dq.back()]+1){
                        dq.push_back(i);
                        flag=0;
                        vis[i]=1;
                        break;
                    }
                }
                if(flag)dq.pop_back();
            }
        }
    }
   // cout<<ans<<endl;
    if(ans>=c)return true;
    return false;
}
int main(){
    while(~scanf("%d%d%d",&k,&c,&m)){
        E=k+c+1;
        init();
        int ans=0,l=0,r=inf;
        while(l<=r){//二分答案
            int mid=(l+r)>>1;
            if(Dinic(mid)){
                r=mid-1;
                ans=mid;
            }
            else l=mid+1;
        }
        cout<<ans<<endl;
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值