网络流之最大流。此题的关键就是建模,看了题目之后一点思路都没有,后来在网上看了解题报告后,才明白了这个过程。首先,在原图中抽象出一个新图。新图是由旧图中的每个milking machine到每个cow的最短路径组成,每条最短路径由原图中的各点间的某些路径组成,抽象为新图中的一条路径,此过程通过floyd算法(各顶点间的最短路径)实现。接下来,就是通过二分来枚举答案。通过给出一个流量的上限,给新图的路径的容量cap赋值,如果小于等于上限cap就为1,反之为0。最后就可将问题转化为新图中,从各milk machine(即源点s)到各cow(即终点t)的最大流(一个流就对应与一头牛)(其实还不完整),如果最大流>=cow的个数,说明当前方案可行,枚举下一个值,最后由二分得到最优解。其中多源多终点问题,可通过加一个超级源和超级终点来转换为一源一终最大流问题。其实,还有一个问题没有解决,就是每台milk machine最大的工作量为m,现在有个超级源就可以很完美的规划为网络流问题。通过设定超级源到每个源点的容量为m,那么由流网络中的流守恒定理可知,从超级源流到各源的上限就是个从各源流出的流的上限,也即各milk machine所能服务的cow的上限。还有一个很明显的问题就是,一个牛肯定只能接受一个流,所以设定各个终点到超级终点的路径的容量设为1。其中最大流算法用的是EK,很慢,但目前还没掌握dinic和isap,这几天要抓紧学啊。
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int maxn=250; const int inf=1<<20;//刚开始inf定义的过大,导致求dis[i][j]时,使两个inf相加的和溢出,得到一个错的dis[i][j],以后要注意这个问题 int dis[maxn][maxn],cap[maxn][maxn],flow[maxn][maxn]; int k,c,m,t; void floyd() { int i,j,k; for(k=1;k<=t;k++) { for(i=1;i<=t;i++) { for(j=1;j<=t;j++) dis[i][j]=dis[i][j]<(dis[i][k]+dis[k][j])?dis[i][j]:(dis[i][k]+dis[k][j]);//防止溢出,所以inf不能定义的过大 } } } void build(int limit) { memset(cap,0,sizeof(cap)); int i,j; for(i=1;i<=k;i++) cap[0][i]=m; for(i=k+1;i<=t;i++) cap[i][t+1]=1; for(i=1;i<=k;i++) { for(j=k+1;j<=t;j++) if(dis[i][j]<inf&&dis[i][j]<=limit) cap[i][j]=1; } } bool ek() { queue<int> q; int a[maxn],p[maxn],tot=0,i; memset(flow,0,sizeof(flow)); for(;;) { memset(a,0,sizeof(a)); a[0]=inf; q.push(0); while(!q.empty()) { int x=q.front(); q.pop(); for(i=0;i<=t+1;i++) { if(!a[i]&&(cap[x][i]-flow[x][i])>0) { p[i]=x; a[i]=a[x]>(cap[x][i]-flow[x][i])?(cap[x][i]-flow[x][i]):a[x]; q.push(i); } } } if(!a[t+1]) break; for(i=t+1;i!=0;i=p[i]) { flow[p[i]][i]+=a[t+1]; flow[i][p[i]]-=a[t+1]; } tot+=a[t+1]; } if(tot<c) return false; else return true; } int binarysearch() { int high=230*200+1,low=0,mid; while(high-low>0) { mid=low+(high-low)/2; build(mid); if(ek()) high=mid; else low=mid+1; } return high; } int main() { while(scanf("%d%d%d",&k,&c,&m)!=EOF) { int i,j; t=k+c; for(i=1;i<=t;i++) { for(j=1;j<=t;j++) { scanf("%d",&dis[i][j]); if(!dis[i][j]&&i!=j) dis[i][j]=inf; } } floyd(); int result=binarysearch(); cout<<result<<endl; } return 0; }