网络流之最大流。此题的关键就是建模,看了题目之后一点思路都没有,后来在网上看了解题报告后,才明白了这个过程。首先,在原图中抽象出一个新图。新图是由旧图中的每个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;
}