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算法讲解博客

https://www.cnblogs.com/SYCstudio/p/7260613.html

猜你喜欢

转载自blog.csdn.net/qq_40642465/article/details/81386946