匈牙利算法和KM算法解决二分图匹配问题

参考博文:

匈牙利算法

1.复杂度:O(n2)

2.适用范围:增广路径求最大匹配,无权图

3.思想: dfs进行匹配,如果匹配冲突,则检查能否改变冲突顶点的配对

4.代码实现:

  • dfs代码模板:
int n,m;
int mp[maxn][maxn],match[maxn],used[maxn];
int dfs(int u)
{
    for(int i = 1; i<=m; i++)
    {
        if(mp[u][i] && !used[i])
        {
            used[i] = 1;
            if(match[i] == -1 || dfs(match[i]))
            {
                match[i] = u;
                return 1;
            }
        }
    }
    return 0;
}
  • 主函数
        int res = 0;
        for(int i = 1; i<=n; i++)
        {
            memset(used, 0, sizeof(used));
            if(dfs(i)) res++;
        }

     

KM算法

1.复杂度:O(n4),可以优化到O(n3)

2.适用范围:带权二分图的最佳匹配

3.思想:见https://www.cnblogs.com/logosG/p/logos.html

4.代码实现:

  • dfs
int mp[maxn][maxn],expx[maxn],expy[maxn],visx[maxn],visy[maxn];
int match[maxn],slack[maxn];
int n,m;
int dfs(int u)
{
    visx[u] = 1;
    for(int i = 1; i<=n; i++)
    {
        if(visy[i] == 0)
        {
            int gap = expx[u] + expy[i] - mp[u][i];
            if(gap == 0)
            {
                visy[i] = 1;
                if(match[i] == -1 || dfs(match[i]))
                {
                    match[i] = u;
                    return 1;
                }
            }
            else slack[i] = min(slack[i],gap);
        }
    }
    return 0;
}
  • KM
    int KM()
    {
        memset(match,-1,sizeof(match));
        memset(expy,0,sizeof(expy));
        for(int i = 1; i<=m; i++)
        {
            expx[i] = 0;
            for(int j = 1; j<=n; j++)
                expx[i] = max(expx[i],mp[i][j]);
        }
        for(int i = 1; i<=m; i++)
        {
            fill(slack+1,slack+1+n,INF);
            while(true)
            {
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(dfs(i))break;
                int d = INF;
                for(int j = 1; j<=n; j++)
                {
                    if(visy[j] == 0) d = min(d,slack[j]);
                }
                for(int j = 1; j<=m; j++)
                    if(visx[j]) expx[j] -=d;
                for(int j = 1; j<=n; j++)
                {
                    if(visy[j]) expy[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        int res = 0;
        for(int i = 1; i<=n; i++)
            res += mp[match[i]][i];
        return res;
    }

猜你喜欢

转载自blog.csdn.net/weixin_41934068/article/details/81270724