Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 14040 | Accepted: 5065 | |
Case Time Limit: 1000MS |
Description
Input
Output
Sample Input
2 3 2 0 3 2 1 1 3 0 3 2 0 2 3 0 1 0 1 2 1 0 2 1 0 0 2 0
Sample Output
2
题意:有k个挤奶器c头奶牛,k个挤奶机位置用编号1到k表示,奶牛位置用k+1到k+c编号来表示。输入是一个矩阵的形式,对角线表示与自身的位置距离为0,其他为0的位置表示没有边相互连接。问怎么安排每个奶牛到某个挤奶器挤奶,使得c头奶牛需要走的所有路程中最大路程最小。
分析:先用floyd算法求出任意两点之间的最短路,然后在用Dinic求出最大流;在搜索最大距离确定最小值时使用二分法。
#include <iostream> #include <stdio.h> #include <string> #include <cstring> #include <algorithm> #include <cmath> #define INF 9999999 #define N 333 using namespace std; int k,m,c; int n; int dis[N][N];//记录两点之间的最短路径 int mp[N][N];//容量网络 int qu[N*100]; int vis[N];//标记数组 int sign[N][N];//层次网络 void build_map(int x) { memset(mp,0,sizeof mp); for(int i=k+1;i<=n;i++) mp[0][i]=1; for(int i=1;i<=k;i++) mp[i][n+1]=m; for(int i=k+1;i<=n;i++) for(int j=1;j<=k;j++) { if(dis[i][j]<=x) mp[i][j]=1; } } int bfs()//构建层次网络 { memset(vis,0,sizeof vis); memset(sign,0,sizeof sign); int qs=0,qe=1; vis[0]=1; qu[0]=0; while(qs<qe) { int v=qu[qs++]; for(int i=0;i<=n+1;i++) { if(vis[i]==0 && mp[v][i]) { vis[i]=1; qu[qe++]=i; sign[v][i]=1; } } } if(vis[n+1]) return 1; else return 0; } int dfs(int v,int sum)//dfs寻找增广路 { if(v==n+1) return sum; int s=sum; int t; for(int i=0;i<=n+1;i++) { if(sign[v][i]) { t=dfs(i,min(sum,mp[v][i])); mp[v][i]-=t; mp[i][v]+=t; sum-=t; } } return s-sum; } int main() { while(~scanf("%d%d%d",&k,&c,&m)) { n=k+c; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&dis[i][j]); if(dis[i][j]==0) dis[i][j]=INF; } for(int t=1;t<=n;t++)//floyd求解最短路 for(int i=1;i<=n;i++) { if(dis[i][t]!=INF) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][t]+dis[t][j]); } int le=0,ri=10009; int ans; while(le<ri)//二分找出最小的最大值 { int mid=(le+ri)/2; ans=0; build_map(mid);//Dinic算法求最大流
while(bfs()) ans+=dfs(0,INF); if(ans>=c) ri=mid; else le=mid+1; } printf("%d\n",ri);//满足条件的最小的mid用于更新ri } return 0; }