zoukankan      html  css  js  c++  java
  • XJOI夏令营501训练1——分配工作

    传送门:QAQQAQ

    题意:某公司有工作人员x1,x2,…,xn ,他们去做工作y1,y2,…,ym(n<=m) ,每个人都能做其中的几项工作,并且对每一项工作都有一个固定的效率。问能否找到一种合适的工作分配方案,使得总的效率最高。要求一个人只能参与一项工作,同时一项工作也必须由一个人独立完成。不要求所有的人都有工作。

    思路:首先让我们明确二分图匹配算法和网络流的区别:二分图KM算法是网络流最小费用最大流中的特例,即KM算法必须满足每一个x点都被匹配才能运行,但两个算法的前提都是在最大匹配的情况下最优,而这道题显然没有要求要最大匹配,所以这两种算法均被否定……(本来想过用最大流做,但发现最大流无法限制x节点只能连一条边)

    所以我们要改进KM算法,我们现在要做的是令所有连边都满足最大匹配的前提,这样效率高低就会成为判断方案优劣的唯一因素。(这种控制无关因素的思路值得借鉴)

    我们现在把每个人干不了的工作都连上0的边,表示这个人干他干他干不了的工作效率为0,这样每个人和每个工作就都有了边,因为m>=n,所以每个人都可以搜到,再跑一遍KM求答案即可。

    (其实这种思路来改进最小费用最大流也可以,但很麻烦,因为网络流中残量网络为0时跑不了)

    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=505;
    const int M=1000001;
    const int inf=(int)2e9;
     
    int E[505][505];
    int match[505],lx[505],ly[505],visx[505],visy[505],slack[505],n,m;
     
    bool dfs(int u)
    {
        visx[u]=1;
        for(int v=1;v<=m;v++)
        {
            if(visy[v]) continue;
            if(lx[u]+ly[v]==E[u][v])
            {
                visy[v]=1;
                if(match[v]==-1||dfs(match[v]))
                {
                    match[v]=u;
                    return 1;
                }
            }
            else
            {
                slack[v]=min(slack[v],lx[u]+ly[v]-E[u][v]);
            }
        }
        return 0;
    }
     
    void EK()
    {
        memset(visx,0,sizeof(visx));
        memset(visy,0,sizeof(visy));
        for(int x=1;x<=n;x++)
        {
            for(int i=1;i<=m;i++) slack[i]=inf;
            while(true)
            {
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(dfs(x)) break;
                int Delta=inf;
                for(int i=1;i<=m;i++) if(!visy[i]) Delta=min(Delta,slack[i]);
                for(int i=1;i<=n;i++) if(visx[i]) lx[i]-=Delta;
                for(int i=1;i<=m;i++) if(visy[i]) ly[i]+=Delta;
                            else slack[i]-=Delta;
            }
        }
    }
     
    int main()
    {
        memset(E,0,sizeof(E));
        memset(ly,0,sizeof(ly));
        memset(match,-1,sizeof(match)); int k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            E[x][y]=max(E[x][y],z);
        }
        for(int i=1;i<=n;i++)
        {
            lx[i]=0;
            for(int j=1;j<=m;j++) lx[i]=max(lx[i],E[i][j]);
        }
        EK();
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            if(match[i]!=-1) ans+=E[match[i]][i];
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    Java SSL证书的安装
    zookeeper集群配置
    ERROR org.apache.zookeeper.ClientCnxn:532
    线程池c3p0和dbcp2的配置初始化实例
    SIP/2.0 403 Forbidden(Invalid domain in From: header)
    OkHttp实现文件上传进度
    Http 缓存机制
    Cookie、Session 和 Token区别
    RecyclerView-- 侧滑删除和拖动排序
    RecyclerView--添加头部和底部
  • 原文地址:https://www.cnblogs.com/Forever-666/p/11182637.html
Copyright © 2011-2022 走看看