poj 2112 Optimal Milking(二分+floyd+最大流)
题目大意就是k个机器和c头牛组成K+C个点,还有个m表示一个机器最多给m头牛服务,然后给你一个(K+C)*(K+C)的矩阵描述了任意2个物体之间的边关系,边权为0表示无边。然后要你在c头牛都能找到机器配对的前提下求c头牛到机器的最远距离的最小值,先把k个机器和c头牛看成是K+C个点,方法就是跑个floyd先求出任意2个点之间的最短距离,然后在二分最远距离的最小值,设low为0,up为100000,这个设的范围包含解在内即可,然后依据mid来建网络流的图,mid表示牛到机器的最远距离,意思是要是i牛到j机器的距离超过了mid,则i牛不能和j机器匹配,即i到j的这条边的容量为0,还有这种多源多汇的最大流还有设个超级源点st,超级汇点et,将et和k个机器连,容量为m(因为每个机器最多服务m头牛),再将st和c头牛连,容量为1,因为1头牛只能匹配一台机器。建完之后就用dinic跑网络了(这也是我第一次用dinic求最大流,没想到一发就过了)。求出来的最大流<c则说明mid太小了,则low=mid+1,否则的话说明最远距离的最小值可能比mid还要小,则up=mid,最后二分搜索结束up就是答案。
#include<iostream>
#include<string.h>
#include<queue>
#include<stdlib.h>
using namespace std;
#define maxn 250
#define inf 0x3f3f3f3f
int dis[maxn][maxn],cap[maxn][maxn],depth[maxn];
int k,c,m;
int n,st,et;
int cnt=0;
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
void build(int maxx)
{
for(int i=0;i<=n+1;i++)//正边反边容量清空
for(int j=i;j<=n+1;j++)
{
cap[i][j]=cap[j][i]=0;
}
for(int i=k+1;i<=n;i++)//建图
cap[st][i]=1;
for(int i=1;i<=k;i++)
cap[i][et]=m;
for(int i=k+1;i<=n;i++)
for(int j=1;j<=k;j++)
{
if(dis[i][j]<=maxx)
{
cap[i][j]=1;
}
}
}
bool bfs()//能不能分层等价于该网络流还有没有增广路
{
queue<int>q;
for(int i=st;i<=et;i++)
depth[i]=0;
depth[st]=1;
q.push(st);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int v=st;v<=et;v++)
if(!depth[v]&&cap[u][v]>0)
{
depth[v]=depth[u]+1;
q.push(v);
}
}
if(depth[et]==0)
return false;
return true;
}
int dfs(int u,int f)
{
if(u==et)
return f;
for(int v=st;v<=et;v++)
{
if((depth[v]==depth[u]+1)&&cap[u][v])
{
int ff=dfs(v,min(f,cap[u][v]));
if(ff>0)
{
cap[u][v]-=ff;
cap[v][u]+=ff;
return ff;
}
}
}
return 0;
}
int dinic()
{
int maxflow=0;
while(bfs())
{
int d;
while(d=dfs(st,inf))
{
//cnt++;
//cout<<"/第"<<cnt<<"/条增广路 "<<d<<endl;
maxflow+=d;
}
}
return maxflow;
}
int main()
{
std::ios::sync_with_stdio(false);
while(cin>>k>>c>>m)
{
if(!k&&!c&&!m) break;
n=k+c;
st=0;
et=k+c+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>dis[i][j];
if(!dis[i][j])
dis[i][j]=inf;
}
floyd();
int low,mid,up,flow;
low=0;
up=10000;
while(low<up)
{
mid=(low+up)>>1;
build(mid);
flow=dinic();
if(flow<c)
low=mid+1;
else
up=mid;
//cout<<"low:"<<low<<" up:"<<up;
//cout<<" maxflow :"<<flow<<endl;
//system("pause");
//cout<<endl;
}
//cout<<"/maxflow "<<flow<<endl;
cout<<up<<endl;
}
}
附上大佬的dinic算法讲解博客