KM算法(DFS版,优化DFS版,BFS版)

KM算法适用于求解二分图的最大权匹配问题,通过加权值处理可转换为最佳匹配问题。本文介绍了KM算法的DFS、优化DFS和BFS三种版本,并提供了各版本的模板及复杂度分析,包括在特定题目中的表现对比。
摘要由CSDN通过智能技术生成

KM算法的前提是图存在一个完备匹配,因此用于二分图的最佳匹配问题。如果是最大权匹配问题,可以通过加权值为0的边来可以将图的最佳匹配与最大全匹配统一起来;如果是最小权匹配问题,可以通过加权值为-INF的边来可以将图的最佳匹配与最大全匹配统一起来(HDU 1853)。见:完美匹配,完备匹配,最佳匹配,最大权匹配
如果我们要求边权值最小的匹配可以把边权值取负值,得出结果后再取相反数即为答案。
KM算法求得的最大权匹配是边权值和最大,如果想要边权之积最大,每条边权取自然对数,然后求最大和权匹配,求得的结果a再算出e^a就是最大积匹配。
题集:
poj 3565
hdu 2255
hdu 1533
hdu 3488 hdu1853 hdu 3435
hdu 2426
hdu 2853
hdu 3718
hdu 3722
hdu 3395
hdu 2282
hdu 2813
hdu 2448
hdu 2236
hdu 3315
hdu 3523
KM算法各版本模板:
dfs版KM算法模板O(n4)复杂度
图解
图解+模板
对访问过且匹配过的男生,期望值要加上女生减去的期望值;代码中的未访问过的男生实际上包含两种,一种是完全没被访问过的(slack[ j ] = INF),一种是访问过,且更新过slack值但没有参与匹配的男生,由于这种男生可匹配的部分女生期望值降低,所以该男生的slack值减少。
HDU 2255 模板

#include <iostream>
#include <cstring>
#include <cstdio>
 
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
// 女生视为左图点,男生视为右图点 
int love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
int ex_girl[MAXN];      // 每个妹子的期望值
int ex_boy[MAXN];       // 每个男生的期望值
bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
int slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
 
int N;
 
 
bool dfs(int girl)
{
   
    vis_girl[girl] = true;
 
    for (int boy = 0; boy < N; ++boy) {
   
 
        if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
 
        int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
 
        if (gap == 0) {
     // 如果符合要求
            vis_boy[boy] = true;
            if (match[boy] == -1 || dfs( match[boy] )) {
       // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
                match[boy] = girl;
                return true;
            }
        } else {
   
            slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
        }
    }
 
    return false;
}
 
int KM()
{
   
    memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
    memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0
 
    // 每个女生的初始期望值是与她相连的男生最大的好感度
    for (int i = 0; i < N; ++i) {
   
        ex_girl[i] = love[i][0];
        for (int j = 1; j < N; ++j) {
   
            ex_girl[i] = max(ex_girl[i], love[i][j]);
        }
    }
 
    // 尝试为每一个女生解决归宿问题
    for (int i = 0; i < N; ++i) {
   
 
        fill(slack, slack + N, INF);    // 因为要取最小值 初始化为无穷大
 
        while (1) {
   
            // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
 
            // 记录每轮匹配中男生女生是否被尝试匹配过
            memset(vis_girl, false, sizeof vis_girl);
            memset(vis_boy, false, 
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值