题目描述:
农场主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("\n")) 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\n",R); } return 0; }