要求所有奶牛中走的距离的最大值的最小值,很容易想到用二分。
先用floyd处理出机器和奶牛之间的距离,再二分出答案一个答案mid,把所有距离小于等于mid的边都加到图里。
源点到所有机器的边的容量为m,机器到奶牛的边(只有距离小于等于mid的边)的容量是1,奶牛到汇点的边的容量是1。
算出最大流,判断最大流是否等于奶牛的个数,然后继续二分。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 999999999
using namespace std;
int dp[235][235],k,c,head[245],e,s,t,m;
struct EDGE
{
int st,to,next,cf;
}edge[6300*2];
void addedge(int u,int v,int val)
{
edge[e].st=u;
edge[e].to=v;
edge[e].cf=val;
edge[e].next=head[u];
head[u]=e++;
edge[e].st=v;
edge[e].to=u;
edge[e].cf=0;
edge[e].next=head[v];
head[v]=e++;
}
void build(int mid)
{
int i,j;
for(i=1;i<=k;i++){
addedge(s,i,m);
for(j=k+1;j<=k+c;j++){
if(dp[i][j]<=mid) addedge(i,j,1);
}
}
for(j=k+1;j<=k+c;j++){
addedge(j,t,1);
}
}
int q[245],qsize,pre[245];
bool vis[245];
bool bfs()
{
memset(vis,0,sizeof(vis));
int i,j,u,v;
qsize=0;
q[qsize++]=s;
vis[s]=1;
for(i=0;i<qsize;i++){
u=q[i];
for(j=head[u];j!=-1;j=edge[j].next){
v=edge[j].to;
if(!vis[v] && edge[j].cf){
vis[v]=1;
q[qsize++]=v;
pre[v]=j;
}
}
}
return vis[t];
}
int EK()
{
int ret=0;
while(bfs()){
int tmp=t,flow=999999999;
while(tmp!=s){
flow=min(flow,edge[pre[tmp]].cf);
tmp=edge[pre[tmp]].st;
}
tmp=t;
while(tmp!=s){
edge[pre[tmp]].cf-=flow;
edge[pre[tmp]^1].cf+=flow;
tmp=edge[pre[tmp]].st;
}
ret+=flow;
}
return ret;
}
int main()
{
int i,j,tmp,l;
scanf("%d%d%d",&k,&c,&m);
s=0;
t=k+c+1;
for(i=1;i<=k+c;i++){
for(j=1;j<=k+c;j++){
scanf("%d",&tmp);
if(!tmp && i!=j){
dp[i][j]=INF;
}
else{
dp[i][j]=tmp;
}
}
}
int left=0,right=-1,mid;
for(l=1;l<=k+c;l++){
for(i=1;i<=k+c;i++){
for(j=1;j<=k+c;j++){
dp[i][j]=min(dp[i][l]+dp[l][j],dp[i][j]);
right=max(right,dp[i][j]);
}
}
}
right++;
int ans;
while(left<=right){
mid=(left+right)>>1;
e=0;
memset(head,-1,sizeof(head));
build(mid);
if(EK()==c){
ans=mid;
right=mid-1;
}
else{
left=mid+1;
}
}
printf("%d\n",ans);
return 0;
}