• 二分图最大权匹配(KM算法)


    #80. 二分图最大权匹配

    统计

    从前一个和谐的班级,有 $n_l$ 个是男生,有 $n_r$ 个是女生。编号分别为 $1, dots, n_l$ 和 $1, dots, n_r$。

    有若干个这样的条件:第 $v$ 个男生和第 $u$ 个女生愿意结为配偶,且结为配偶后幸福程度为 $w$。

    请问这个班级里幸福程度之和最大是多少?

    输入格式

    第一行三个正整数,$n_l, n_r, m$。

    接下来 $m$ 行,每行三个整数 $v, u, w$ 表示第 $v$ 个男生和第 $u$ 个女生愿意结为配偶,且幸福程度为 $w$。保证 $1 leq v leq n_l$,$1 leq u leq n_r$,保证同一对 $v, u$ 不会出现两次。

    输出格式

    第一行一个整数,表示幸福程度之和的最大值。

    接下来一行 $n_l$ 个整数,描述一组最优方案。第 $v$ 个整数表示 $v$ 号男生的配偶的编号。如果 $v$ 号男生没配偶请输出 $0$。

    样例一

    input

    2 2 3
    1 1 100
    1 2 1
    2 1 1
    
    

    output

    100
    1 0
    
    

    限制与约定

    $1 leq n_l, n_r leq 400$,$1 leq m leq 160000$,$1 leq w leq 10^9$。

    时间限制:$1 exttt{s}$

    空间限制:$256 exttt{MB}$

     递归版ed1

    //用时        内存    语言    文件大小
    //1787ms    1276kb    C++        1.7kb
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    using namespace std;
    typedef long long ll;
    const int N=505;
    const int inf=1e9+99;
    template<typename T>
    inline void read(T &x){
        register bool f=0;register char ch=getchar();x=0;
        for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
        for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
        if(f) x=-x;
    }
    template<typename T,typename...Args>
    void read(T &x,Args&...args){read(x);read(args...);}
    #define m(x) memset(x,0,sizeof x);
    bool visx[N],visy[N];
    int nx,ny,n,m,slap[N],lx[N],ly[N],match[N],w[N][N];
    bool hunguary(int x){
        visx[x]=1;
        for(int y=1;y<=n;y++){
            if(visy[y]) continue;
            int gap=lx[x]+ly[y]-w[x][y];
            if(!gap){
                visy[y]=1;
                if(!match[y]||hunguary(match[y])){
                    match[y]=x;
                    return 1;
                }
            }
            else slap[y]=min(slap[y],gap);
        }
        return 0;
    }
    ll KM(){
        for(int i=1;i<=n;i++) lx[i]=*max_element(w[i]+1,w[i]+n+1);
        for(int x=1;x<=n;x++){
            fill(slap+1,slap+n+1,inf);
            m(visx);m(visy);
            if(hunguary(x)) continue;
            while(1){
                int d=inf,t=0;
                for(int y=1;y<=n;y++) if(!visy[y]) d=min(d,slap[y]);
                for(int x=1;x<=n;x++) if(visx[x]) lx[x]-=d;
                for(int y=1;y<=n;y++) if(visy[y]) ly[y]+=d;else if(!(slap[y]-=d)) t=y;
                if(!match[t]) break;
                int v=match[t];
                visx[v]=visy[t]=1;
                for(int y=1;y<=n;y++) slap[y]=min(slap[y],lx[v]+ly[y]-w[v][y]);
            }
            m(visx);m(visy);
            hunguary(x);
        }
        ll res=0;
        for(int i=1;i<=n;i++) res+=w[match[i]][i];
        return res;
    }
    int main(){
        read(nx,ny,m);n=max(nx,ny);
        for(int i=0,x,y,z;i<m;i++) read(x,y,z),w[y][x]=z;
        printf("%lld
    ",KM());
        for(int i=1;i<=nx;i++) printf("%d ",w[match[i]][i]?match[i]:0);
        return 0;
    }

    循环版ed2

    //用时        内存    语言    文件大小
    //1758ms    1792kb    C++        1.1kb
    #include<stdio.h>
    #include<iostream>
    using namespace std;
    template<typename T>
    inline void read(T &x){
        register bool f=0;register char ch=getchar();x=0;
        for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
        for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
        if(f) x=-x;
    }
    template<typename T,typename...Args>
    void read(T &x,Args&...args){read(x);read(args...);}
    const int N=404,inf=1e9;
    bool vy[N];long long ans;
    int n,m,n1,n2,lx[N],ly[N],w[N][N],mt[N],sl[N],pre[N];
    int main(){
        read(n1,n2,m);n=max(n1,n2);
        for(int i=0,x,y,z;i<m;i++) 
            read(x,y,z),w[y][x]=z,lx[y]=max(lx[y],z);
        for(int i=1,x,d,py,pn;i<=n;i++){
            for(int j=1;j<=n;j++) sl[j]=inf,vy[j]=0;
            for(mt[py=0]=i;mt[py];py=pn){
                vy[py]=1;d=inf;x=mt[py];
                for(int y=1;y<=n;y++) if(!vy[y]){
                    if(lx[x]+ly[y]-w[x][y]<sl[y])
                        sl[y]=lx[x]+ly[y]-w[x][y],pre[y]=py;
                    if(sl[y]<d) d=sl[y],pn=y;
                }
                for(int y=0;y<=n;y++)
                    vy[y]?lx[mt[y]]-=d,ly[y]+=d:sl[y]-=d;
            }
            for(;py;py=pre[py]) mt[py]=mt[pre[py]];
        }
        for(int i=1;i<=n;i++) ans+=lx[i]+ly[i];
        printf("%lld
    ",ans);
        for(int i=1;i<=n1;i++) printf("%d ",w[mt[i]][i]?mt[i]:0);
        return 0;
    }
  • 相关阅读:
    【转】常用 Java 静态代码分析工具的分析与比较
    转-SQL Server系列-我感觉自己不用写了,很清晰很有条理
    转-SQL Server Alwayson概念总结
    超级快的python vibora.io框架
    [转]做超炫图表,数据可视化的优雅实现方案 (硬核科普)
    统计资料下载论坛
    [FW]Windows7 Python-3.6 安装PyCrypto(pycrypto 2.6.1)出现错误以及解决方法
    国内外常用公共NTP网络时间服务器
    HTTP Error 500.24
    step7 microwin v4.0 sp9 win7 64位首次安装s7-200的软件,首次使用西门子软件,每次提示这个信息,怎么解决,网上有说,倒入注册表信息,按照下图进行操作还是不行,求各位高手指点一下,谢谢!
  • 原文地址:https://www.cnblogs.com/shenben/p/12255765.html
Copyright © 2020-2023  润新知