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版本就是来自于这个文章。