KM算法实现带权匹配C#版本和C++两个版本实现O^3

C# 版本

using System;
using System.Collections.Generic;
using System.Text;

namespace Agorithm
{
    public struct KMConst
    {
        public const int MaxN = 101;
        public const int INF = 1000000000+7;
        public const int NPOS = -1;
    }

    public class KmMatrix
    {
        public int[,] W = new int[KMConst.MaxN, KMConst.MaxN];
        public int[] Lx = new int[KMConst.MaxN];
        public int[] Ly = new int[KMConst.MaxN];
        public int[] MatchY = new int[KMConst.MaxN];
        public int[] VisX = new int[KMConst.MaxN];
        public int[] VisY = new int[KMConst.MaxN];
        public int[] Slack = new int[KMConst.MaxN];
        public int Nx { get; set; }
        public int Ny { get; set; }

        protected void Memset(int[] arr, int ini)
        {
            for(int i =0; i< arr.Length; i++)
            {
                arr[i] = ini;
            }
        }

    }

    /// <summary>
    /// 使用km算法返回最带权匹配
    /// </summary>
    public class KuhnMunkres : KmMatrix
    {
        public KuhnMunkres(int x, int y)
        {
            Nx = x;
            Ny = y;
        }

        bool Find(int x)
        {
            VisX[x] = 1;
            for (int y = 0; y < Ny; y++)
            {
                if (VisY[y]==1)
                    continue;
                int t = Lx[x] + Ly[y] - W[x,y];
                if (t == 0)
                {
                    VisY[y] = 1;
                    if (MatchY[y] == -1 || Find(MatchY[y]))
                    {
                        MatchY[y] = x;
                        return true;//找到增广轨
                    }
                }
                else if (Slack[y] > t)
                    Slack[y] = t;
            }
            return false;//没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
        }

        public int KM()//返回最优匹配的值
        {
            int i, j;
            Memset(MatchY, -1);
            Memset(Ly, 0);
            for (i = 0; i < Nx; i++)
                for (j = 0, Lx[i] = -KMConst.INF; j < Ny; j++)
                    if (W[i,j] > Lx[i])
                        Lx[i] = W[i,j];
            for (int x = 0; x < Nx; x++)
            {
                for (i = 0; i < Ny; i++)
                    Slack[i] = KMConst.INF;
                while (true)
                {
                    Memset(VisX, 0);
                    Memset(VisY, 0);
                    if (Find(x))//找到增广轨,退出
                        break;
                    int d = KMConst.INF;
                    for (i = 0; i < Ny; i++)//没找到,对l做调整(这会增加相等子图的边),重新找
                    {
                        if (!(VisY[i]!=0) && d > Slack[i])
                            d = Slack[i];
                    }
                    for (i = 0; i < Nx; i++)
                    {
                        if (VisX[i]!=0)
                            Lx[i] -= d;
                    }
                    for (i = 0; i < Ny; i++)
                    {
                        if (VisY[i]!=0)
                            Ly[i] += d;
                        else
                            Slack[i] -= d;
                    }
                }
            }
            int result = 0;
            for (i = 0; i < Ny; i++)
                if (MatchY[i] > -1)
                    result += W[MatchY[i],i];
            return result;
        }
    }
}

在这里插入图片描述

int maxn = 4; 
KuhnMunkres km = new KuhnMunkres(maxn, maxn); 
// 初始化权重
int maxn = 4; 
KuhnMunkres km = new KuhnMunkres(maxn, maxn); 
// 初始化权重
km.W[0, 0] = 2;
km.W[0, 1] = 5;
km.W[0, 2] = 1;
km.W[0, 3] = 0;
km.W[1, 0] = 8;
km.W[1, 1] = 3;
km.W[1, 2] = 9;
km.W[1, 3] = 0;
km.W[2, 0] = 4;
km.W[2, 1] = 9;
km.W[2, 2] = 2;
km.W[2, 3] = 0;
km.W[3, 0] = 3;
km.W[3, 1] = 5;
km.W[3, 2] = 6;
km.W[3, 3] = 0;
int maxWeight = km.KM(); // 获取最大权
var matchs = km.MatchY.ToList().Where(p=>p!=-1).ToList(); // 获取匹配

输出 maxWeight = 23
matchs = {1,2,3,0};
即最大权匹配
(1,0) = 8;
(2,1) = 9;
(3,2) = 6;
(0, 3) = 0;

C++ 版本

#include<pch.h>
#include <iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
const int MaxN = 101;
const int INF = (1 << 31) - 1;
int W[MaxN][MaxN];
int Lx[MaxN], Ly[MaxN]; //顶标
int MatchY[MaxN];
int VisX[MaxN], VisY[MaxN];
int Slack[MaxN];
int Nx, Ny;
bool find(int x)
{
    VisX[x] = true;
    for (int y = 0; y < Ny; y++)
    {
        if (VisY[y])
            continue;
        int t = Lx[x] + Ly[y] - W[x][y];
        if (t == 0)
        {
            VisY[y] = true;
            if (MatchY[y] == -1 || find(MatchY[y]))
            {
                MatchY[y] = x;
                return true;        //找到增广轨
            }
        }
        else if (Slack[y] > t)
            Slack[y] = t;
    }
    return false;                   //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
}

int KM()                //返回最优匹配的值
{
    int i, j;
    memset(MatchY, -1, sizeof(MatchY));
    memset(Ly, 0, sizeof(Ly));
    for (i = 0; i < Nx; i++)
        for (j = 0, Lx[i] = -INF; j < Ny; j++)
            if (W[i][j] > Lx[i])
                Lx[i] = W[i][j];
    for (int x = 0; x < Nx; x++)
    {
        for (i = 0; i < Ny; i++)
            Slack[i] = INF;
        while (true)
        {
            memset(VisX, 0, sizeof(VisX));
            memset(VisY, 0, sizeof(VisY));
            if (find(x))                     //找到增广轨,退出
                break;
            int d = INF;
            for (i = 0; i < Ny; i++)          //没找到,对l做调整(这会增加相等子图的边),重新找
            {
                if (!VisY[i] && d > Slack[i])
                    d = Slack[i];
            }
            for (i = 0; i < Nx; i++)
            {
                if (VisX[i])
                    Lx[i] -= d;
            }
            for (i = 0; i < Ny; i++)
            {
                if (VisY[i])
                    Ly[i] += d;
                else
                    Slack[i] -= d;
            }
        }
    }
    int result = 0;
    for (i = 0; i < Ny; i++)
        if (MatchY[i] > -1)
            result += W[MatchY[i]][i];
    return result;
}

int main()
{
    while (true)
    {
        Nx = 4;
        Ny = 4;
        W[0][0] = 2;  W[0][1] = 5;   W[0][2] = 1;  W[0][3] = 0; 
        W[1][0] = 8;   W[1][1] = 3;   W[1][2] = 9;  W[1][3] = 0;  
        W[2][0] = 4;  W[2][1] = 9;  W[2][2] = 2; W[2][3] = 0; 
        W[3][0] = 3;   W[3][1] = 5;  W[3][2] = 6; W[3][3] = 0; 
        printf("%d\n", KM());
        break;
    }
    return 0;
}

具体KM实现步骤可以参考https://blog.csdn.net/u013044116/article/details/45228057
本文的C版本就是来自于这个文章。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值