题目链接:http://poj.org/problem?id=2112
题目大意:
有K台挤奶机器(1...K编号)和C头奶牛(K+1...K+C编号),每台挤奶机器可以给M头奶牛挤奶;
给出一个(K+C)*(K+C)的矩阵表示机器和奶牛两两之间的距离;
要求求出把奶牛运送到机器的最大流中的奶牛路径中的最短路径;
思路:
首先对给出的矩阵用Floyd求出机器奶牛两两之间的最短距离,记录其中最大值right和最小值left,通过二分搜索的方法,构建容量网络求出最大流,最大流即为能运送的奶牛的最大数目,如果最大流等于奶牛数C,返回路径值即可。
#include<iostream>
using namespace std;
const int inf=100000000;
int s,t;
int n,m;
int cap[250][250];//容量网络
int dist[250][250];
int K,C,M;
/*BFS+标记法求范围内最大流*/
int maxflow()
{
int queue[250];
int head,tail;
int pre[250]; //结点i的前驱
int minflow;
int flow=0;
int x,y;
while(true)
{
memset(pre,-1,sizeof(pre));
for(queue[head=tail=0]=s;head<=tail;head++)
{
x=queue[head];
for(int i=0;i<=t;i++)//当汇点还没有被标记时
{
if (cap[x][i]>0 && pre[i]==-1) //当结点u指向i的边存在,且i还没有标记前驱时
{
pre[i]=x;//记录结点i的前驱为u
queue[++tail]=i;
}
if(pre[t]!=-1)
break;
}
}
if(pre[t]==-1)
break;//BFS后汇点没有被标记,则跳出while,已经不存在增广链
minflow=inf;//初始化
for(x=pre[y=t];y!=s;)//回溯
{
if(cap[x][y] < minflow)
minflow=cap[x][y];//寻找当前增广链中最小容量的边,记录其边权(容量)
y=x;
x=pre[y];
}
for(x=pre[y=t];y!=s;) //当前增广链 流量调整
{
cap[x][y] -= minflow; //正向弧容量减少
cap[y][x] += minflow; //反向弧容量增加
y=x;
x=pre[y];
}
flow += minflow; //最大流=每次寻得的增广链的调整量之和
}
return flow;//返回最大流
}
bool solve(int x)
{
int i,j;
/*Structure Graph*/
memset(cap,0,sizeof(cap));
for(i=1;i<=C;i++)
cap[0][i]=1;
for(i=K+1;i<t;i++)
{
for(j=1;j<=K;j++)
{
if(dist[i][j]<=x)
cap[i-K][C+j]=1;
}
}
for(i=1;i<=K;i++)
cap[C+i][t]=M;
if(maxflow()==C)
return true;
else
return false;
}
int main(int i,int j,int k)
{
while(~scanf("%d %d %d",&K,&C,&M))
{
t=K+C+1;
s=0;
/*Input*/
for(i=1;i<t;i++)
{
for(j=1;j<t;j++)
{
scanf("%d",&dist[i][j]);
if(dist[i][j]==0)
dist[i][j]=inf;
}
}
/*Floyd Algorithm*/
for(k=1;k<t;k++)
{
for(i=1;i<t;i++)
{
for(j=1;j<t;j++)
{
if(dist[i][j]>dist[i][k]+dist[k][j])
dist[i][j]=dist[i][k]+dist[k][j];
}
}
}
int left=inf;
int right=0;
for(i=1;i<=K;i++)
{
for(j=K+1;j<t;j++)
{
if(dist[i][j]!=inf && dist[i][j]>right)
right=dist[i][j];
if(dist[i][j]!=inf && dist[i][j]<left)
left=dist[i][j];
}
}
/*二分搜索*/
while(left<right)
{
int mid=(left+right)/2;
if(solve(mid))
right=mid;
else
left=mid+1;
}
printf("%d\n",right);
}
return 0;
}