KM算法【带权二分图完美匹配】

先orz litble——KM算法

为什么要用KM算法

因为有的题丧心病狂卡费用流

KM算法相比于费用流来说,具有更高的效率。

算法流程

我们给每一个点设一个期望值【可行顶标】

对于左边的点来说,就是期望能匹配到多大权值的右边的点

对于右边的点来说,就是期望能在左边的点的期望之上还能产生多少贡献

两个点能匹配,当且仅当它们的期望值之和为这条边的权值

一开始初始化所有左点的期望是其出边的最大值,因为最理想情况下当然是每个点都匹配自己能匹配最大的那个

右点期望为0

然后我们逐个匹配,当一个点匹配失败时,所有左点的期望就过高了

我们从右点未匹配的点中找到离被匹配相差的期望最小的点,所有此次匹配涉及的左点减去这个期望值【使得能匹配的点多出了一个】,然后其匹配的右点要加上这个期望值【因为还要保证已匹配的点仍然能被匹配】

然后继续尝试匹配

直至所有点匹配完

板子:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 405,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int w[maxn][maxn],expa[maxn],expb[maxn],visa[maxn],visb[maxn],cp[maxn],dl[maxn];
int n;
bool dfs(int u){
    visa[u] = true;
    REP(i,n) if (!visb[i]){
        int kl = expa[u] + expb[i] - w[u][i];
        if (kl == 0){
            visb[i] = true;
            if (!cp[i] || dfs(cp[i])){
                cp[i] = u; return true;
            }
        }
        else dl[i] = min(dl[i],kl);

    }
    return false;
}
int solve(){
    REP(i,n) expa[i] = expb[i] = cp[i] = 0;
    REP(i,n) REP(j,n) expa[i] = max(expa[i],w[i][j]);
    REP(i,n){
        REP(j,n) dl[j] = INF;
        while (true){
            REP(j,n) visa[j] = false,visb[j] = false;
            if (dfs(i)) break;
            int kl = INF;
            REP(j,n) if (!visb[j]) kl = min(kl,dl[j]);
            REP(j,n){
                if (visa[j]) expa[j] -= kl;
                if (visb[j]) expb[j] += kl;
                else dl[j] -= kl;
            }
        }
    }
    int re = 0;
    REP(i,n) re += w[cp[i]][i];
    return re;
}
int main(){
    n = read();
    REP(i,n) REP(j,n) w[i][j] = read();
    printf("%d\n",solve());
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8994980.html

时间: 2024-10-12 03:04:28

KM算法【带权二分图完美匹配】的相关文章

KM(Kuhn-Munkres)算法求带权二分图的最佳匹配

KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后,这些概念的意义和背后的作用就渐渐的显示出来了.因此,先暂时把相关概念列出来,看看,有个大概印象就好,等到了解了算法的流程后,在看原理中会有这些概念,那个时候回来细看就好了. 完备匹配:定义 设G=<V1,V2,E>为二部图,|V1|≤|V2|,M为G中一个最大匹配,且|M|=|V1|,则称M为V1

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

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

费用流模板(带权二分图匹配)——hdu1533

/* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 10005 #define maxm 200005 struct Edge{int to,nxt,w,c;}e[maxm<<1]; int head[maxn],tot,n,m,s,t,ans,maxflow; char mp[maxn][maxn]; vector<pair<int,int&

UVA 1045 - The Great Wall Game(二分图完美匹配)

UVA 1045 - The Great Wall Game 题目链接 题意:给定一个n*n的棋盘,有n个棋子在上面,现在要移动棋子,每一步代价是1,现在要把棋子移动到一行,一列,或者在主副对角线上,问最小代价 思路:二分图完美匹配,枚举每种情况,建边,边权为曼哈顿距离,然后km算法做完美匹配算出值即可,由于要求最小值所以边权传负数,这样做出来的值的负就是答案 代码: #include <cstdio> #include <cstring> #include <cmath&g

UVA 11383 - Golden Tiger Claw(二分图完美匹配扩展)

UVA 11383 - Golden Tiger Claw 题目链接 题意:给定每列和每行的和,给定一个矩阵,要求每个格子(x, y)的值小于row(i) + col(j),求一种方案,并且所有行列之和的和最小 思路:A二分图完美匹配的扩展,行列建二分图,权值为矩阵相应位置的值,做一次KM算法后,所有顶标之和就是最小的 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algor

UVA 10888 - Warehouse(二分图完美匹配)

UVA 10888 - Warehouse option=com_onlinejudge&Itemid=8&page=show_problem&category=562&problem=1829&mosmsg=Submission+received+with+ID+14222079" target="_blank" style="">题目链接 题意:就是推箱子游戏,问最少要几步 思路:每一个箱子和目标位置建边.

UVA 1411 - Ants(二分图完美匹配)

UVA 1411 - Ants 题目链接 题意:给定一些黑点白点,要求一个黑点连接一个白点,而且全部线段都不相交 思路:二分图完美匹配,权值存负的欧几里得距离,这种话,相交肯定比不相交权值小,所以做一次完美匹配就能够了 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXNODE = 1

二分图与网络流 带权二分图的最大匹配

二分图与网络流  带权二分图的最大匹配 在某书上偶然发现,二分图和网络流是有联系的,在子图u中建立超级源点,在子图v中建立超级汇点,源点到u和汇点到v的每条边容量设为1,u和v中的边的容量也设为1,求出最大流也就是原二分图的最大匹配了. 而求带权二分图的最大匹配也就很容易了,将u和v的权值设为容量,仍然建立超级源点和超级汇点转为网络流解决即可. 真是一切皆可网络流啊...

POJ 1904 King&#39;s Quest强连通分量+二分图完美匹配

题目描述: Description Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were young and light-headed, so i