KM算法用来求解二分图的最大(小)权匹配,即最优(佳)匹配。
该算法是通过给每一个顶点标号将求最大匹配问题转化为求完备匹配的问题。
设顶点Xi的顶标为A[ i ],顶点Yj的顶标为B[ j ],顶点Xi与Yj之间的边权为w[i,j]。在算法执行过程中的任一时刻,对于任一条边(i,j),A[ i ]+B[j]>=w[i,j]始终成立。
KM算法的正确性基于以下定理:
若由二分图中所有满足A[ i ]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
首先解释下什么是完备匹配,所谓的完备匹配就是在二部图中,X点集中的所有点都有对应的匹配或者是
Y点集中所有的点都有对应的匹配,则称该匹配为完备匹配。
这个定理是显然的。因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和。所以相等子图的完备匹配一定是二分图的最大权匹配。
二分图最优匹配模板(KM算法)
/*其实在求最大 最小的时候只要用一个模板就行了,把边的权值去相反数即可得到另外一个.求结果的时候再去相反数即可*/
/*最大最小有一些地方不同。。*/
#include <iostream>
//赤裸裸的模板啊。。
const int maxn = 101;
const int INF = (1<<31)-1;
int w[maxn][maxn];
int lx[maxn],ly[maxn]; //顶标
int linky[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(linky[y]==-1 || find(linky[y]))
{
linky[y] = x;
return true; //找到增广轨
}
}
else if(slack[y] > t)
slack[y] = t;
}
return false; //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
}
int KM() //返回最优匹配的值
{
int i,j;
memset(linky,-1,sizeof(linky));
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++)
result += w[linky[i]][i];
return result;
}
int main()
{
char c;
int man[maxn][2],home[maxn][2];
int i,j;
int n,m;
while(true)
{
scanf("%d %d",&n,&m);
if(n==0&&m==0) break;
nx = ny = 0;
getchar();
for(i = 0; i < n; i++)
{
for(j = 0; j < m; j++)
{
c = getchar();
if(c == 'm')
{
man[nx][0] = i;
man[nx][1] = j;
nx++;
}
else if(c == 'H')
{
home[ny][0] = i;
home[ny][1] = j;
ny++;
}
}
getchar();
}
for(i = 0; i < nx; i++)
for(j = 0; j < ny; j++)
w[i][j] = (abs(man[i][0]-home[j][0]) + abs(man[i][1]-home[j][1]))*(-1);
printf("%d\n",KM()*(-1));
}
return 0;
}
其实,二分图的最优匹配还可以用网络流(最大流)来解决,但KM算法更为简洁。
见POJ2195。
分享到:
相关推荐
**KM算法详解** KM算法,也称为Kuhn-Munkres算法或匈牙利算法,是图论中的一个经典算法,主要用于解决最优加权二分匹配问题。在许多实际场景中,如作业分配、任务调度、资源分配等,都可以找到它的应用。在MATLAB...
二分图匹配、匈牙利算法以及KM算法是图论中的关键概念,主要应用于寻找最大匹配问题。在解决这些问题时,这些算法能有效地找到在给定条件下的最优解。 首先,二分图(Bi-partite Graph)是图论中的一种特殊类型,其...
**KM算法** KM算法,全称为Karmarkar's算法,是由印度计算机科学家 Narendra Karmarkar 在1984年提出的一种解决线性规划问题的内点法。相较于传统的单纯形法,KM算法在计算速度上有显著优势,尤其是在解决大规模...
这种问题被称为带权二分图的最优匹配问题,可由KM算法解决。 比如上图,A做工作a的效率为3,做工作c的效率为4......以此类推。 不了解KM算法的人如何解决这个问题?我们只需要用匈牙利算法找到所有的最大匹配,...
【KM算法】,也称为K均值算法,是一种在数据挖掘和机器学习领域广泛应用的无监督聚类方法。它的核心思想是将数据集分成K个不同的簇,使得每个数据点尽可能地归属于与其最近的簇中心。这个过程通过迭代来完成,直至簇...
二分图最大匹配及最大权匹配(km算法) 本文将详细介绍二分图最大匹配及最大权匹配(km算法),涵盖了增广路定理、Hall定理、匈牙利树算法、Edmonds-Karp算法、Hopcroft算法等相关知识点。 一、二分图最大匹配 在...
km算法的c++程序,能够跑通,是值得新手直接上手的程序
### 二分图最大匹配KM算法详解 #### KM算法概览 KM算法(Kuhn-Munkres Algorithm),也称为匈牙利算法的扩展版本,主要用于解决带权二分图的最佳匹配问题。简单来说,二分图是一种特殊的图结构,它可以被划分为两个...
"最大流高标号法KM算法" 最大流高标号法KM算法是对最大流问题的一种改进算法,主要使用类似单源最短路径的方式进行改进。该算法首先遍历生成一棵广度优先生成树,然后在寻找每一条增光路的最大流,总的加起来就是...
二分图的最优匹配(KM 算法) KM 算法是解决最大权匹配问题的经典算法,在二分图中寻找最大权匹配的问题。该算法的基本原理是通过给每个顶点一个标号(称做顶标)来把求最大权匹配的问题转化为求完备匹配的问题。 ...
二分图匹配-匈牙利算法和KM算法简介 二分图的概念:在图论中,二分图是指一个无向图G=(V,E),其中顶点集V可以分割为两个互不相交的子集,且图中每条边依附的两个顶点都属于不同的子集。二分图的这种特性使得它在...
KM算法可以计算二分图的最大权匹配,匈牙利算法可以计算最大匹配
km算法的C++实现,以及调用DEMO,通过取邻接矩阵的相反数可以实现最小权匹配
本文将深入探讨二分图、最大匹配、匈牙利算法以及KM算法。 首先,理解二分图的概念至关重要。二分图是指一个无向图的顶点集可以被分为两个互不相交的子集X和Y,使得每条边连接的两个顶点分别属于这两个不同的子集。...
KM算法用于求二部图最大权匹配,该程序的输入是二分图两边节点的数和一个矩阵 矩阵的行和列应该相等,当二分图的两边节点数不一样时,以数值大的节点为准,不存在的边的权赋值为0。 比如:一边是2个点(v1,v2),...
本资源介绍了二分图,二分图的最大匹配,二分图的完备匹配,二分图的最佳匹配。 以及介绍了 匈牙利算法,KM算法的步骤。并且有详细的图解,方便理解。
二分图(匈牙利,KM算法详解).pptx
基于Dijkstra算法和KM算法的网约车订单分配问题的输入文件https://blog.csdn.net/weixin_40679158/article/details/121475235
km 实现最小权值组合
【KM算法】,也称为K-means算法,是数据挖掘领域中最常见的聚类算法之一。它的主要目的是将数据集划分为K个不同的类别,使得每个类别内的数据点彼此相似,而类别之间的差异最大化。KM算法的基本步骤包括初始化质心、...