poj 2112 Optimal Milking(二分搜索+最大流)

来源:互联网 发布:制作手机视频的软件 编辑:程序博客网 时间:2024/05/29 18:50

题目链接: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;elsereturn 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;elseleft=mid+1;}printf("%d\n",right);}return 0;}


原创粉丝点击