最优的挤奶方案(Optimal Milking)
时间限制: 1 Sec 内存限制: 128 MB题目描述
农场主 John 将他的 K(1≤K≤30)个挤奶器运到牧场,在那里有 C(1≤C≤200)头奶牛,在奶
牛和挤奶器之间有一组不同长度的路。K个挤奶器的位置用1~K的编号标明,奶牛的位置用K+1~
K+C 的编号标明。
每台挤奶器每天最多能为 M(1≤M≤15)头奶牛挤奶。
编写程序,寻找一个方案,安排每头奶牛到某个挤奶器挤奶,并使得 C 头奶牛需要走的所有
路程中的最大路程最小。每个测试数据中至少有一个安排方案。每条奶牛到挤奶器有多条路。
输入
第 1 行为 3 个整数 K、C 和 M。
第 2~K+C+1 行,每行有 K+C 个整数,描述了奶牛和挤奶器(二者合称实体)之间的位置,
这 K+C 行构成了一个沿对角线对称的矩阵。第 2 行描述了第 1 个挤奶器离其他实体的距离,…,
第 K+1 行描述了第 K 个挤奶器离其他实体的距离;第 K+2 行描述了第 1 头奶牛离其他实体的距
离,…。这些距离为不超过 200 的正数。实体之间如果没有直接路径相连,则距离为 0。实体与
本身的距离(即对角线上的整数)也为 0。
输出
输出一个整数,为所有方案中,C 头奶牛需要走的最大距离的最小值。
样例输入
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
样例输出
2
题解:
又是一道网络流套二分的题目。
1.先用floyd求一个最短路map。
2.每一次虚拟一个源点和挤奶器建边,虚拟一个汇点和奶牛建边。
3.Dinic跑起来!!!
4.然后。。。就没有然后了。。。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<stack> #include<ctime> #include<vector> using namespace std; int n,m,l,s; int map[301][301],cap[301][301],depth[301]; int read() { int ans=0,f=1; char i=getchar(); while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} return ans*f; } bool bfs() { memset(depth,0,sizeof(depth)); int b[30001],head=0,tail=0,i; b[tail++]=0; depth[0]=1; while(head!=tail) { int x=b[head++]; for(i=0; i<=s+1; i++) { if(depth[i]==0&&cap[x][i]>0) { depth[i]=depth[x]+1; b[tail++]=i; } } } if(depth[s+1]!=0)return 1; else return 0; } int dfs(int root,int flow) { if(root==s+1)return flow; int res=0; for(int i=0; i<=s+1; i++) { if(cap[root][i]>0&&depth[i]==depth[root]+1) { int tmp=dfs(i,min(flow-res,cap[root][i])); cap[root][i]-=tmp; cap[i][root]+=tmp; res+=tmp; if(res==flow)return flow; } } return res; } bool judge(int mid) { memset(cap,0,sizeof(cap)); int i,j,k; for(i=1; i<=n; i++) cap[0][i]=l; for(i=1; i<=n; i++) for(j=n+1; j<=s; j++) if(map[i][j]<=mid) cap[i][j]=1; for(i=n+1; i<=s; i++) cap[i][s+1]=1; int root=0,f=0; while(bfs()) { f+=dfs(root,2000000000); } return f>=m; } int main() { int i,j,k; n=read(); m=read(); l=read(); s=n+m; for(i=1; i<=s; i++) for(j=1; j<=s; j++) { map[i][j]=read(); if(map[i][j]==0)map[i][j]=2e8; } for(k=1; k<=s; k++) for(i=1; i<=s; i++) for(j=1; j<=s; j++) if(i!=j&&j!=k&&k!=i&&map[i][k]+map[k][j]<map[i][j]) map[i][j]=map[i][k]+map[k][j]; int l=0,r=5000000,ans=5000000; while(l<=r) { int mid=(l+r)>>1; if(judge(mid)) { ans=mid; r=mid-1; } else l=mid+1; } printf("%d ",ans); return 0; }
总结:
1.最大值不能赋太大,否则会溢出。
2.最好还是用非递归的Dinic。