zoukankan      html  css  js  c++  java
  • poj 2112 Optimal Milking(最大流+二分 或者 二分图多重匹配)

    题目链接:http://poj.org/problem?id=2112

    题意:有n个挤奶机,m头奶牛,每个挤奶机最多处理k头奶牛。给出挤奶机、奶牛之间的距离,问完成挤奶任务后,使走最远距离奶牛最小化,并输出。

    思路:最远距离最小化,很容易知道时二分处理。但是二分判定条件是什么呢?

    二分距离成立的情况是 使所以奶牛都可以到挤奶机。这样变成了一个二分图匹配的问题,左边是n个挤奶机,  右边是m头奶牛,每个奶牛都要匹配一个挤奶机。又因为挤奶机有匹配个数的,就是二分图多重匹配了。只要最大匹配数量是奶牛的头数m则这个二分距离是成立的。(二分图多重匹配)

    当然,用网络流最大流也是可以完成的,二分图一般都可以用网络流。那怎么建图呢?

    只要建两个虚点,一个起点,一个终点,起点连接每个挤奶机,流量是k,每头奶牛连接终点,流量为1,而根据二分距离判定挤奶机是否可以连接奶牛,可以则流量是1。只要最大流是m,则说明二分距离是可以的。

    当然这里的点与点之间的距离用floyed计算即可.

    二分图多重匹配代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=350;
    int mp[maxn][maxn];
    bool used[maxn];
    int cnt[maxn];//cnt[i]记录现在第i个挤奶机有多少个奶牛
    int mat[maxn][maxn],n,m,k;//mat[i][j]表示第i个挤奶机第j个匹配的奶牛是谁 
    int g[maxn][maxn];
    
    bool dfs(int x)//匹配 
    {
        for(int i=1;i<=n;i++)
        {
            if(mp[x][i]&&!used[i])//表示第x个奶牛可以匹配第i个挤奶机 
            {
                used[i]=1;
                if(cnt[i]<k)//并且该挤奶机数量未上限,直接匹配 
                {
                    mat[i][cnt[i]++]=x;
                    return true;
                }
                else//人数上限,查找该挤奶机上所以奶牛是否可以让位置 
                {
                    for(int j=0;j<k;j++)
                    {
                        if(dfs(mat[i][j]))//可以让位置 
                        {
                            mat[i][j]=x;
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    bool solve() 
    {
        for(int i=n+1;i<=n+m;i++)//查看是否所以奶牛可以匹配 
        {
            for(int j=1;j<=n;j++)
                used[j]=0;
            if(!dfs(i))//i奶牛不能匹配 
                return false;
        }
        return true;
    }
    
    bool check(int x)//判断条件,距离为x是否成立 
    {
        memset(cnt,0,sizeof(cnt));
        memset(mp,0,sizeof(mp));
        for(int i=1;i<=n;i++)
            for(int j=n+1;j<=m+n;j++)
                if(g[i][j]<=x)
                    mp[i][j]=mp[j][i]=1;
        if(solve())
            return true;
        return false;
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n+m;i++)
        {
            for(int j=1;j<=n+m;j++)
            {
                scanf("%d",&g[i][j]);
                if(i!=j&&!g[i][j])
                    g[i][j]=inf;
            }
        }
        for(int k=1;k<=n+m;k++)//floyed求最短距离 
            for(int i=1;i<=n+m;i++)
                for(int j=1;j<=n+m;j++)
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]);    
                            
        int l=0,r=inf,mid;
        while(r>=l)//二分结果 
        {
            mid=(r+l)/2;
            if(check(mid))
                r=mid-1;    
            else
                l=mid+1;
        }
        printf("%d
    ",l);
        return 0;
    }
    View Code

    网络流代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=350;
    int g[maxn][maxn];
    struct node{
        int u,v,w,nxt;
    }e[maxn*maxn];
    int h[maxn],depth[maxn],n,m,k,st,ed;
    int cnt;
    
    void add(int u,int v,int w)//建图,记得建反向边 
    {
        e[cnt].v=v;e[cnt].w=w;
        e[cnt].nxt=h[u];h[u]=cnt++;
        
        e[cnt].v=u,e[cnt].w=0;
        e[cnt].nxt=h[v];h[v]=cnt++;
    }
    
    bool bfs(){//dinic--分层图 
        queue<int> que;
        memset(depth,0,sizeof(depth));
        que.push(st);
        depth[st]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            if(u==ed)
                return true;
            for(int i=h[u];i!=-1;i=e[i].nxt){
                int v=e[i].v;
                int w=e[i].w;
                if(!depth[v]&&w){
                    depth[v]=depth[u]+1;
                    que.push(v);
                }
            }
        }
        return false;
    }
    
    int dfs(int u,int dis) 
    {
        if(u==ed)
            return dis;
        int res=0;
        for(int i=h[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            int w=e[i].w;
            if((depth[v]==depth[u]+1)&&w)
            {
                int di=dfs(v,min(w,dis-res));
                e[i].w-=di;
                e[i^1].w+=di;
                res+=di;
                if(res==dis)
                    return dis;
            }
        }
        return res;
    }
    
    int dinic()//dinic求最大流 
    {
        int ans=0;
        while(bfs())
        {
            ans+=dfs(st,inf);
        }
        return ans;
    }
    
    bool check(int x)
    {
        cnt=0;
        memset(h,-1,sizeof(h));
        for(int i=1;i<=n;i++)//挤奶机和奶牛是否可以连接 
            for(int j=n+1;j<=n+m;j++)
                if(g[i][j]<=x)
                    add(i,j,1);
        for(int i=1;i<=n;i++)//起点连挤奶机 
            add(st,i,k);
        for(int i=n+1;i<=m+n;i++)//奶牛连终点 
            add(i,ed,1);
        int ans=dinic();
        if(ans==m)//最大流是奶牛头数 
            return true;
        return false;
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n+m;i++)
        {
            for(int j=1;j<=n+m;j++)
            {
                scanf("%d",&g[i][j]);
                if(i!=j&&!g[i][j])
                    g[i][j]=inf;
            }
        }
        for(int k=1;k<=n+m;k++)
            for(int i=1;i<=n+m;i++)
                for(int j=1;j<=n+m;j++)
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]);            
        st=0,ed=n+m+1;//建起点,终点 
        int l=0,r=inf,mid;
        while(r>=l)
        {
            mid=(r+l)/2;
            if(check(mid))
                r=mid-1;    
            else
                l=mid+1;
        }
        printf("%d
    ",l);
        return 0;
    }
    View Code
  • 相关阅读:
    Java 动态编译
    在ubuntu 18.04下,无线网卡无驱动,连不上wifi,显示wifi没有适配器的解决方法
    由浅入深了解Thrift(1,2,3)
    Docker系列05:docker镜像制作 &Docker file
    Docker系列04:docker数据存储
    Docker系列03:docker网络
    关于在github上 下载源码 clone 非 master 分支的代码
    CentOS 6 & 7 忘记root密码的修改方法
    Windows RDP远程连接CentOS 7
    Windows 上用IntelliJ Idea调试百度大数据分析框架Apache Doris FE
  • 原文地址:https://www.cnblogs.com/xiongtao/p/11298846.html
Copyright © 2011-2022 走看看