码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2020-02-03 16:04:16      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:内存   ade   space   algo   测试   bool   sub   ret   fine   

#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\texttt{s}$

空间限制:$256\texttt{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\n",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\n",ans);
    for(int i=1;i<=n1;i++) printf("%d ",w[mt[i]][i]?mt[i]:0);
    return 0;
}

 

 

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

标签:内存   ade   space   algo   测试   bool   sub   ret   fine   

原文地址:https://www.cnblogs.com/shenben/p/12255765.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!