题目大意:农场有k个挤奶器,每个挤奶器最多容纳m头奶牛,所有奶牛和挤奶器之间的距离已知,安排奶牛挤奶方案使得所有奶牛中走的最大距离最小化。
利用最大流来做,奶牛和挤奶器看做图中节点,先用floyd算出每个节点之间的最小距离,二分最大距离d,然后建图,边长大于d的都去掉,然后建立网络,引入源点和汇点,源点到每个奶牛节点连接一条容量为一的边,挤奶器节点与汇点连接一条容量为m的边,奶牛节点与挤奶器节点间连接容量为一的边(如果之间有边的话),然后求最大流,不断二分。
代码为dinic算法
#include <stdio.h> #include <string.h> #define MAX 300 #define INF 10000000 int dis[MAX][MAX],map[MAX][MAX]; bool sign[MAX][MAX],used[MAX]; int K,C,n,M; int min(int a,int b) { if(a>b) return b; else return a; } void build(int mid) { int i,j; memset(map,0,sizeof(map)); for(i=K+1;i<=n;i++) map[0][i]=1; for(i=1;i<=K;i++) map[i][n+1]=M; for(i=K+1;i<=n;i++) { for(j=1;j<=K;j++) if(dis[i][j]<=mid) map[i][j]=1; } } bool bfs() { memset(used,0,sizeof(used)); memset(sign,0,sizeof(sign)); int queue[100*MAX]={0}; queue[0]=0; used[0]=1; int t=1,f=0; while(f<t) { for(int i=0;i<=n+1;i++) { if(!used[i]&&map[queue[f]][i]) { queue[t++]=i; used[i]=1; sign[queue[f]][i]=1; } } f++; } if(used[n+1]) return true; else return false; } int dfs(int v,int sum) { int i,s,t; if(v==n+1) return sum; s=sum; for(i=0;i<=n+1;i++) { if(sign[v][i]) { t=dfs(i,min(map[v][i],sum)); map[v][i]-=t; map[i][v]+=t; sum-=t; } } return s-sum; } int main() { int i,j,k,l,r,mid,ans; scanf("%d%d%d",&K,&C,&M); 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]; l=0;r=10000; while(l<r) { mid=(l+r)/2; ans=0; build(mid); while(bfs()) ans+=dfs(0,INF); if(ans>=C) r=mid; else l=mid+1; } printf("%d\n",r); return 0; }