题意:有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离。现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶牛的路程最短的方案。
构图:先Floyd求所有点对之间最短路,二分最短长度,若奶牛与挤奶机之间的距离大于mid则不连边,否则连容量为1的边。源向挤奶机连容量M的边,奶牛向汇连容量1的边,用最大流判可行性。
View Code
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; #define V 300 #define E 30000 #define inf 0xffff int map[V][V]; struct Edge { int u,v,c,next; }edge[E]; int n,m,cnt; int dist[V]; int head[V]; int que[V]; int sta[V]; int s,t; void init(){ cnt=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int c){ edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c; edge[cnt].next=head[u];head[u]=cnt++; edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0; edge[cnt].next=head[v];head[v]=cnt++; } int dinic(int s,int t){ int ans=0; while(true){ int left,right,u,v; memset(dist,-1,sizeof(dist)); left=right=0; que[right++]=s; dist[s]=0; while(left<right){ u=que[left++]; for(int k=head[u];k!=-1;k=edge[k].next){ u=edge[k].u; v=edge[k].v; if(edge[k].c > 0 && dist[v]==-1){ dist[v]=dist[u]+1; que[right++]=v; if(v==t){ left=right; break; } } } } if(dist[t]==-1) break; int top=0; int now=s; while(true){ if(now!=t){ int k; for(k=head[now];k!=-1;k=edge[k].next){ if(edge[k].c>0 && dist[edge[k].v]==dist[edge[k].u]+1) break; } if(k!=-1){ sta[top++]=k; now=edge[k].v; } else{ if(top==0) break; dist[edge[sta[--top]].v]=-1; now=edge[sta[top]].u; } } else{ int flow=inf,ebreak; for(int i=0;i<top;i++){ if(flow>edge[sta[i]].c){ flow=edge[sta[i]].c; ebreak=i; } } ans+=flow; for(int i=0;i<top;i++){ edge[sta[i]].c-=flow; edge[sta[i]^1].c+=flow; } now=edge[sta[ebreak]].u; top=ebreak; } } } return ans; } int main() { //freopen("in.txt","r",stdin); int k,c,m; while(scanf("%d%d%d",&k,&c,&m)!=EOF){ for(int i=1;i<=k+c;i++) for(int j=1;j<=k+c;j++){ scanf("%d",&map[i][j]); if(map[i][j]==0) map[i][j]=inf; if(i==j) map[i][j]=0; } for(int z=1;z<=k+c;z++) 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][z]+map[z][j]); /*for(int i=1;i<=k+c;i++) { for(int j=1;j<=k+c;j++) { cout << map[i][j] << " "; } cout << endl; }*/ int l=0,r=inf,mid,res; while(l<r){ mid=(l+r)/2; init(); for(int i=1;i<=k;i++) addedge(0,i,m); for(int i=1;i<=k;i++) for(int j=k+1;j<=k+c;j++) if(map[i][j]<=mid) addedge(i,j,1); for(int j=k+1;j<=k+c;j++) addedge(j,k+c+1,1); int ans=dinic(0,k+c+1); if(ans==c) r=mid,res=mid; else l=mid+1; } printf("%d\n",res); } return 0; }