题目地址:http://poj.org/problem?id=2112
一般一堆数中最大值的最小值用二分查找,就是先假设一个数,在求一下看看符不符合题意,如果符合就缩小范围
建图方法如下:
每个奶牛和挤奶器都是一个节点,添加一个源,连边到所有奶牛节点,这些边容量都是1。
添加一个汇点,每个挤奶器都连边到它。这些边的容量都是M。
再每次根据Dinic算法求出的最大流是不是C来判断,如下:
先假定一个最大距离的的最小值 maxdist, 在上述图中,如果奶牛节点i和挤奶器节点j之间的距离<=maxdist,
则从i节点连一条边到j节点,表示奶牛i可以到挤奶器j去挤奶。该边容量为1。该图上的最大流如果是C(奶牛数),
那么就说明假设的 maxdist成立,则减小 maxdist再试总之,要二分 maxdist, 对每个maxdist值,都重新构图,
看其最大流是否是C,然后再决定减少或增加maxdist
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=230+5;
const int INF=1000000000;
int G[maxn][maxn];
int dist[maxn][maxn];
int p[maxn][maxn];
bool vis[maxn];
int layer[maxn]; //记录层次
int Floyd(int n)
{for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(p[i][j]==0) dist[i][j]=INF;else dist[i][j]=p[i][j];}for(int k=1;k<=n;k++) //中间经过k-1个点for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
bool getLayer(int s,int t) //分层
{queue<int> Q;memset(layer,0,sizeof(layer));layer[s]=1;Q.push(s);while(!Q.empty()){int u=Q.front(); Q.pop();for(int v=s;v<=t;v++)if(G[u][v]>0&&!layer[v]){layer[v]=layer[u]+1;if(v==t) return true; //一旦到终点m就不必分层了 Q.push(v);} }return false;
}
int Dinic(int s,int t)
{int MaxFlow=0;while(getLayer(s,t)){deque<int> DQ; //保存路径 memset(vis,0,sizeof(vis));vis[s]=1;DQ.push_back(s);while(!DQ.empty()){int u=DQ.back();if(u==t) //找到增广路径了,便找出最小流,更新网络流,添加反向边 {int MinFlow=INF; //最小流 int pMin; //最小流的上一个节点位置 for(int i=1;i<DQ.size();i++){int u=DQ[i-1];int v=DQ[i];if(G[u][v]>0&&MinFlow>G[u][v]) //找出最小流 {MinFlow=G[u][v];pMin=u; } }MaxFlow+=MinFlow; //累加到最大流 for(int i=1;i<DQ.size();i++){int u=DQ[i-1];int v=DQ[i];G[u][v]-=MinFlow; //更新最小流 G[v][u]+=MinFlow; //添加反向边 }while(!DQ.empty()&&DQ.back()!=pMin){ //退栈到PMin,回溯继续找增广路径 vis[DQ.back()]=0;DQ.pop_back();}continue;}int ok=0;for(int v=s;v<=t;v++)if(G[u][v]>0&&!vis[v]&&layer[v]==layer[u]+1) //只能走到下一层 {ok=1;vis[v]=1;DQ.push_back(v);break; }if(!ok) DQ.pop_back(); //不能走就pop,换一条路走 } }return MaxFlow;
}
int solve(int dis,int K,int C,int M)
{int s=0,t=K+C+1;memset(G,0,sizeof(G));for(int i=1;i<=K;i++) G[s][i]=M;for(int i=K+1;i<=K+C;i++) G[i][t]=1;for(int i=1;i<=K;i++)for(int j=K+1;j<=K+C;j++)if(dist[i][j]<=dis) G[i][j]=dis;return Dinic(s,t);
}
int BinarySearch(int K,int C,int M)
{Floyd(K+C);int L=1,R=50000,mid,ans;while(L<=R){mid=(L+R)/2;if(solve(mid,K,C,M)==C) ans=mid,R=mid-1;else L=mid+1;}return ans;
}
int main()
{int K,C,M;cin>>K>>C>>M;for(int i=1;i<=K+C;i++)for(int j=1;j<=K+C;j++)cin>>p[i][j];cout<<BinarySearch(K,C,M);return 0;
}