二分图匹配KM算法

Kuhn-Munkres算法

KM算法,求完备匹配下的最大权匹配,时间复杂度O(\(n^3\))
所谓的完备匹配就是在二部图中,x点集中的所有点都有对应的匹配 且 y点集中所有的点都有对应的匹配 ,则称该匹配为完备匹配

算法思想

(1)初始化可行顶标的值;
(2)用匈牙利算法寻找完备匹配;
(3)若未找到完备匹配则修改可行顶标的值;
(4)重复(2)(3)直到找到相等子图的完备匹配为止。

模板

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 310;
const int M = 1e9+7;
int n,m,k,t;

int a[maxn][maxn];          //图
int ex_x[maxn];         //x期望能匹配到的y值
int ex_y[maxn];         //y期望能匹配到的x值
bool vis_x[maxn];           //标记是否访问
bool vis_y[maxn];           //标记是否访问
int match[maxn];        //y的匹配
int slack[maxn];        //y的松弛,记录y最少还差多少期望值


bool dfs(int x)
{
    vis_x[x] = 1;
    for(int y = 0; y <= y; y++)
    {
        if(vis_y[y]) continue;

        int gap = ex_x[x]-ex_y[y]-a[x][y];

        if(gap == 0)        //如果符合要求
        {
            vis_y[y] = 1;
            if(match[y] == -1 || dfs(match[y]))     //如果y没有被匹配,或者y的x可以换另一个y
            {
                match[y] = x;
                return true;
            }
        }
        else        //不符合要求,我还差gap的期望值才能有匹配
        {
            slack[y] = min(slack[y],gap);
        }
    }
}


int km()
{
    mem(match,-1);mem(ex_y,0);      //y期望的x是0
    mem(ex_x,0);            //初始化
    for(int i = 0; i < n; i++)      //x期望的y是最大的那个
    {
        for(int j = 0; j < n; j++)
        {
            ex_x[i] = max(ex_x[i],a[i][j]);
        }
    }

    for(int i = 0; i < n; i++)
    {
        mem(slack,inf);
        while (1)
        {
            mem(vis_x,0);mem(vis_y,0);
            if(dfs(i)) break;       //找到匹配

            //如果找不到
            int d = inf;
            for(int j = 0; j < n; j++)
            {
                if(!vis_y[j])   d = min(d,slack[j]);
            }

            for(int j = 0; j < n; j++)      //降低期望
            {
                if(vis_x[j]) ex_x[j] -= d;      

                if(vis_y[j]) ex_y[j] += d;
                else slack[j] -= d;
            }
        }
    }

    int res = 0;
    for(int i = 0; i < n; i++)
    {
        res += a[match[i]][i];
    }
    return res;
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
#endif
    while (~cin(n))
    {
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                cin(a[i][j]);
            }
        }
        printf("%d\n",km());
    }
    return 0;
}

例题

http://acm.hdu.edu.cn/showproblem.php?pid=2255

参考博客

https://www.cnblogs.com/wenruo/p/5264235.html
https://baike.baidu.com/item/KM算法

原文地址:https://www.cnblogs.com/hezongdnf/p/12076192.html