二分图最大权匹配(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\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;
}

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

时间: 2024-12-11 04:46:59

二分图最大权匹配(KM算法)的相关文章

二分图 最大权匹配 km算法

这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配. 这个定理是显然的.因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和:如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和.所以相等子图的完备匹配一定是二分图的最大权匹配. (1)可行点标:每个点有一个标号,记lx[i]为X方点i的标号,l

HDU3488 Tour —— 二分图最大权匹配 KM算法

题目链接:https://vjudge.net/problem/HDU-3488 Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3720    Accepted Submission(s): 1777 Problem Description In the kingdom of Henryy, there are N (2 <=

带权二分图的最大权匹配 KM算法模版

带权二分图的最大权匹配 KM算法模版 下面是kuangbin大神的模版,已通过西电oj1048的测试 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set

POJ 2195 二分图最小权匹配KM算法

本来是打算昨天晚上写的, 昨天网速渣的连CSDN都进不去,没办法 只能现在来写了 先写写对KM算法的理解,KM算法是对每个点设置一个顶标,只有当边长等于两边点的顶标之和的时候才进行增广,这样就能保证得到的一定是最大权匹配. 如果找不到匹配的时候就对交替路中X集合的顶标减少一个d Y集合的顶标增加一个d. 这样两个点都在交替路中的时候x[i]+y[i]的和不边 X在 Y不在的时候x[i]+y[i]减少,可能就会为图增加一对匹配. X不在Y在的时候x[i]+y[i]增加, 原来不在现在依然不在其中.

poj 2195 Going Home 二分图最小权匹配KM算法

题意: 有n个人要回到n间房子里,每间房子只允许一个人,求n个人要走的最小距离和. 分析: 裸的二分图最小权匹配,KM搞之. 代码: //poj 2195 //sep9 #include <iostream> using namespace std; const int maxN=128; char g[maxN][maxN]; int mx[maxN],my[maxN],hx[maxN],hy[maxN]; int w[maxN][maxN]; int lx[maxN],ly[maxN],l

HDU 3722 Card Game(二分图最佳完美匹配+KM算法)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3722 1 /* 2 问题 3 将任意的两个字符串进行匹配,使得匹配后权值和最大 4 5 解题思路 6 将任意的字符串的权值计算出来,使用KM算法即可. 7 */ 8 #include<cstdio> 9 #include<cstring> 10 #include<algorithm> 11 using namespace std; 12 13 const int maxn

hdu 2426 Interesting Housing Problem 最大权匹配KM算法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2426 For any school, it is hard to find a feasible accommodation plan with every student assigned to a suitable apartment while keeping everyone happy, let alone an optimal one. Recently the president of

网络流——二分图最优匹配KM算法

前言 其实这个东西只是为了把网络流的内容凑齐而写的(反正我是没有看到过这样子的字体不知道田忌赛马算不算) 算法过程 我们令左边的点(其实二分图没有什么左右)为女生,右边的点为男生,那么: 为每一个女生定一个心仪值,心仪值为她与男生连边中的最大值 为每一个女生找对象,要求男生的心仪值和女生的心仪值的和为他们的边权(男生的心仪值初始为0真惨) 如果没有找到对象,那么将2过程中的女生的心仪值全部-Min,男生的心仪值全部+Min(这个Min是通过自己算的,就是女生除了之前或当前心仪的男生外最心仪的男生

[ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)

奔小康赚大钱 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊. 村里共同拥有n间房间,刚好有n家老百姓,考虑到每家都要有房住(假设有老百姓没房子住的话.easy引起不安定因素),每家必须分配到一间房子且仅仅能得到一间房子. 还有一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.因为老百姓都比較富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比方有3间房