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
题意:有K个挤奶机器和C头牛,每个挤奶机器可以给M头牛挤奶,给出一个(K+C)*(K+C)的矩阵,前K行表示第i个挤奶机到其他点的距离,后C行表示第i头牛到其他点的距离。问,在所有的牛都可以被挤奶的前提下,走得最远的那头牛所走的距离最小。(有点拗口,也就是说,满足所有牛都可以被挤奶的方案有很多。所以,不同方案下,这些牛中,走的最远的那头牛需要走的距离也可能不一样,找出最小的那种情况)
思路:我们先来考虑怎么使得每头牛都可以被挤奶,如果把牛看做流量的话,如果所有的牛都被挤奶了 ,那么最大流=牛的数量。所以,我们引入超级源点,超级汇点,将源点向牛连边(流量为1),然后将牛向机器连边(流量为1),最后将机器向汇点连边(流量为M)。这样就可以跑最大流来判断牛是否可以全部被挤奶了。然后我们可以通过二分枚举答案了,在建边的时候,如果距离大于mid那么就不进行连边,如果最大流大于C说明边还可以小,那么令r=mid-1.否则令l=mid+1;最后的mid就是答案了。
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=1e9+10;
int K,C,M,e;
int Map[250][250],dis[250],head[250];
void init()
{
e=0;
memset(head,-1,sizeof head);
}
struct EDGE
{
int to,flow,next;
};
EDGE edge[200000];
void add(int u,int v,int f)//前向星建边
{
edge[e].to=v,edge[e].flow=f;
edge[e].next=head[u];
head[u]=e++;
edge[e].to=u,edge[e].flow=0;
edge[e].next=head[v];
head[v]=e++;
}
void floyd()//floyd预先跑出所有点之间的距离
{
for(int k=1;k<=K+C;k++)
for(int i=1;i<=K+C;i++)
for(int j=1;j<=K+C;j++){
Map[i][j]=min(Map[i][j],Map[i][k]+Map[k][j]);
}
}
bool bfs(int s)//dinic给图打标记分层
{
memset(dis,-1,sizeof dis);
queue<int> que;
dis[s]=0;
que.push(s);
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to,f=edge[i].flow;
if(dis[v]<0&&f>0){
dis[v]=dis[u]+1;
que.push(v);
}
}
}
return dis[K+C+1]>0;
}
int dfs(int u,int Min)//按分层寻找曾广路径
{
if(u==K+C+1) return Min;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to,f=edge[i].flow;
if(f>0&&dis[v]==dis[u]+1){
int a=dfs(v,min(Min,f));
if(a>0){
edge[i].flow-=a;
edge[i^1].flow+=a;//反弧加流
return a;
}
}
}
return 0;
}
int dinic()
{
int ans=0,tmp;
while(bfs(0)){
while(tmp=dfs(0,inf)){
ans+=tmp;
}
}
return ans;
}
void solve()
{
int l,r,mid,ans;
l=0,r=inf;
while(l<=r){//二分枚举
mid=(l+r)>>1;
init();
for(int i=K+1;i<=K+C;i++)
for(int j=1;j<=K;j++){
if(Map[i][j]<=mid) add(i,j,1);
}
for(int i=1;i<=K+C;i++){
if(i>=K+1) add(0,i,1);
else if(i<=K) add(i,K+C+1,M);
}
if(dinic()==C){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<endl;
}
int main()
{
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(Map[i][j]==0) Map[i][j]=inf;
}
floyd();
solve();
}
return 0;
}