题目描述:
农场主John将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C≤200)头奶牛,在奶
牛和挤奶器之间有一组不同长度的路。K个挤奶器的位置用1~K的编号标明,奶牛的位置用K+1~
K+C的编号标明。
每台挤奶器每天最多能为M(1≤M≤15)头奶牛挤奶。
编写程序,寻找一个方案,安排每头奶牛到某个挤奶器挤奶,并使得C头奶牛需要走的所有
路程中的最大路程最小。每个测试数据中至少有一个安排方案。每条奶牛到挤奶器有多条路。
// 本题的求解算法:先用Floyd算法求出能达到的任意两点之间的最短路径,然后用Dinic算法
// 求最大流;搜索最大距离的最小值采用二分法进行。
// 建图问题 : 给个源点 s 。源点到奶牛的流量为1 如果奶牛到达挤奶器距离在max_min范围内 那没就然 该奶牛到该挤奶器的流量为1
// 再给个汇点 那么挤奶器到汇点的流量就是M 正好符合限制
/// 然后二分查找 max_min就可以了
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MOD 1000000007
#define INF 1000000000
#define maxn 310
#define maxm 48010
#define LL __int64//long long
int M,K,C,N;
int cap[maxn][maxn],flow[maxn][maxn];
int dis[maxn][maxn];//,bl[1100];
void build(int max_min){ // 建图
int i,j;
memset(cap,0,sizeof(cap));
memset(flow,0,sizeof(flow));
for(i=1;i<=K;i++) cap[i][N+1]=M;
for(i=K+1;i<=N;i++) cap[0][i]=1;
for(i=K+1;i<=N;i++)
for(j=1;j<=K;j++)
if(dis[i][j]<=max_min) cap[i][j]=1;
}
int level[maxn];
bool BFS(int s,int t){
memset(level,0,sizeof(level));
queue<int> Q;
int u;
int i;
Q.push(s);
level[s]=1;
while(!Q.empty()){
u=Q.front();
Q.pop();
if(u==t) return true;
for(i=1;i<=t;i++)
if(!level[i]&&cap[u][i]>flow[u][i])
{
level[i]=level[u]+1;
Q.push(i);
}
}
return false;
}
int dfs(int u,int maxf,int t){
if(u==t||maxf==0) return maxf;
int ret=0,f,i;
for(i=1;i<=t;i++)
if(cap[u][i]>flow[u][i]&&level[u]+1==level[i]){
f= dfs(i,min(maxf,cap[u][i]-flow[u][i]),t);
flow[u][i]+=f;
flow[i][u]-=f;
maxf-=f;
ret+=f;
if(maxf==0) break;
}
return ret;
}
int Dinic(int s,int t){
int flow=0;
while(BFS(s,t)){
flow+=dfs(s,INF,t);
}
return flow;
}
void init(){
// memset(cap,0,sizeof(cap));
// memset(flow,0,sizeof(flow));
}
int main(){
int i,j,k;
while(scanf("%d %d %d",&K,&C,&M)!=EOF){
N=K+C;
for(i=1;i<=N;i++)
for(j=1;j<=N;j++){
scanf("%d",&dis[i][j]);
if(dis[i][j]==0) dis[i][j]=INF;
}
for(k=1;k<=N;k++)
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
if(dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j];
/* for(i=0;i<=N+1;i++,printf("
"))
for(k=0;k<=N+1;k++)
printf("%d ",cap[i][k]);*/
int L=0,R=100000,mid;
int tp;
while(L<R){// 二分枚举 max_min
mid=(L+R)>>1;
build(mid);
tp=Dinic(0,N+1);
if(tp>=C) R=mid;
else L=mid+1;
}
printf("%d
",R);
}
return 0;
}