本文参考博客:
http://blog.csdn.net/zhangpinghao/article/details/12242823(代码参考该博客)
http://philoscience.iteye.com/blog/1754498(个人认为对km算法讲解比较好)

KM算法求的是基于带权二分图中完备匹配下的最大权值匹配。关于km算法的讲解网上资料比较丰富,此处就不详述啦。这里主要整理一些用KM算法求最小权值匹配的一些问题。

  • 在求最大权值匹配时,不存在的边的权值设为0。在求最小权值匹配时,可以考虑将对应的权值变为相反数,或者用一个很大的数减去权值,然后再来求最大权值匹配,最后将权值和取反即可。如果使用将对应的权值变为相反数的方法,则不存在的边的权值此时要设为INT_MAX(即,实际中求匹配时使用的是-INT_MAX),如此设置之后还需要特别注意溢出的问题, if( !sy[j] && ((lx[i] + ly[j] - weight[i][j] )<inc) 这一句对于带符号整型数可能会溢出,所以此句可以改成if( !sy[j] && weight[i][j]!=-INT_MAX && ((lx[i] + ly[j] - weight[i][j] )<inc),即不予考虑不存在的边。

  • 注意,km算法求的是完备匹配,即x集中的点数m与y集中的点数n不一定相同,但m<=n,最终结果是给x集合中的每一个值都找到一个y中的匹配。

  • 如果一个y集合中的点最多可以对应n个x集合中的点,则可以将y中的点数拓展n倍,最后变成一一对应的关系。

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <limits.h>using namespace std;  #define MAX 100  int m,n;    //x集与y集的点数
int weight[MAX][MAX];           //边的权重
int lx[MAX],ly[MAX];            //期望值,定点标号
bool sx[MAX],sy[MAX];           //记录寻找增广路时点集x,y里的点是否搜索过
int match[MAX];                 //match[i]记录y[i]与x[match[i]]相对应  bool search_path(int u) {          //给x[u]找匹配,这个过程和匈牙利匹配是一样的  int v;sx[u]=true;         for(v=0; v<n; v++){  if(!sy[v] &&lx[u]+ly[v] == weight[u][v]){   //对于还没搜索过的且在相等子图中的点  sy[v]=true;  //标记一下表示搜索过if(match[v]==-1 || search_path(match[v])){  //名花无主或者还能腾出个位置(使用递归)  match[v]=u;  return true;  }  }  }  return false;
}  int Kuhn_Munkras(bool max_weight){  //表示求最大匹配(1)还是最小匹配(0)int i,j,u,inc,sum;if(!max_weight){ //如果求最小匹配,则要将边权取反  for(i=0;i<m;i++)  for(j=0;j<n;j++)  weight[i][j]=-weight[i][j];  }  //初始化顶标,lx[i]设置为max(weight[i][j] | j=0,..,n-1 ), ly[i]=0;  for(i=0;i<m;i++){  lx[i]=-0x7fffffff;  for(j=0;j<n;j++)  if(lx[i]<weight[i][j])  lx[i]=weight[i][j];  }  for(j=0;j<n;j++)ly[j]=0;memset(match,-1,sizeof(match));  //不断修改顶标,直到找到完备匹配或完美匹配  for(u=0;u<m;u++){   //为x里的每一个点找匹配  while(1){  memset(sx,0,sizeof(sx));  memset(sy,0,sizeof(sy));  if(search_path(u))       //x[u]在相等子图找到了匹配,继续为下一个点找匹配  break;  //如果在相等子图里没有找到匹配,就修改顶标,直到找到匹配为止  //首先找到修改顶标时的增量inc, min(lx[i] + ly [i] - weight[i][j],inc);,lx[i]为搜索过的点,ly[i]是未搜索过的点,因为现在是要给u找匹配,所以只需要修改找的过程中搜索过的点,增加有可能对u有帮助的边  inc=0x7fffffff;  for(i=0;i<m;i++){if(sx[i])        //x是搜索过的点for(j=0;j<n;j++){if(!sy[j]&&((lx[i] + ly [j] - weight[i][j] )<inc)) inc = lx[i] + ly [j] - weight[i][j] ;  //y是未搜索过的点}}//找到增量后修改顶标,因为sx[i]与sy[j]都为真,则必然符合lx[i] + ly [j] =weight[i][j],然后将lx[i]减inc,ly[j]加inc不会改变等式,但是原来lx[i] + ly [j] !=weight[i][j]即sx[i]与sy[j]最多一个为真,lx[i] + ly [j] 就会发生改变,从而符合等式,边也就加入到相等子图中  if(inc==0)  cout<<"fuck!"<<endl;  //都无法求其次,简直不可理喻,所以找不到完备匹配for(i=0;i<m;i++){  if(sx[i])     lx[i]-=inc;      //所有已搜索过的x减少相同的量,便于给其他的x找其他的路径}for(i=0;i<n;i++){if(sy[i])  ly[i]+=inc;       //对应的ly[]加上inc使得Lx[]+Ly[]与weight[]始终保持一致}  }  }  sum=0;  for(i=0;i<n;i++)  if(match[i]>=0)  sum+=weight[match[i]][i];  if(!max_weight)  sum=-sum;  return sum;  }int main(){  int i,j;printf("请输入X集与Y集的点数:M,N\n");scanf("%d%d",&m,&n);  printf("请输入权重\n");for(i=0;i<m;i++)  for(j=0;j<n;j++)  scanf("%d",&weight[i][j]);printf("%d\n",Kuhn_Munkras(0));  for(i=0;i<n;i++)printf("%d ",match[i]);system("pause");  return 0;
}

一些重要概念的补充:

  • 二分图:顶点分为两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。
  • 最大匹配:图中包含边数最多的匹配称为图的最大匹配。(这个时候不涉及权值)
  • 完备匹配与完美匹配:G=< V1, V2, E >,|V1|<=|V2|,M为G中的一个最大匹配,且|M|=|V1|,则称M为V1到V2的完备匹配,若|V2|=|V1|,则完备匹配即为完美匹配,若|V1|<|V2|,则完备匹配为G中的最大匹配。
  • 匈牙利算法:用增广路求二分图的最大匹配。
  • KM算法:利用匈牙利算法求完备匹配下的最大权重匹配。

利用Kuhn-Munkras算法求最小权值匹配相关推荐

  1. 小A与欧拉路 (树加边求最小权值欧拉路+树的直径)

    链接:https://ac.nowcoder.com/acm/contest/369/C 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...

  2. POJ-2195 Going Home 最小权值匹配

    题意:给定一个网格图,图上有一些人要到一些房子当中去,人和房子的数量一样多,人和房子的曼哈顿距离作为行走的开销,问所有人走到房子中的最小开销. 解法:将人和房子之间两两之间建立带权边,权值为曼哈顿距离 ...

  3. poj 3565 uva 1411 Ants KM算法求最小权

    由于涉及到实数,一定,一定不能直接等于,一定,一定加一个误差<0.00001,坑死了-- 有两种事物,不难想到用二分图.这里涉及到一个有趣的问题,这个二分图的完美匹配的最小权值和就是答案.为啥呢 ...

  4. HDU 1853 HDU 3488【有向环最小权值覆盖问题 】带权二分图匹配 KM算法

    HDU 1853 & HDU 3488[有向环最小权值覆盖问题 ]最小费用最大流 In the kingdom of Henryy, there are N (2 <= N <= ...

  5. HDU6346(最小权值完美匹配)

    题意:满足 xi+yj≤ai,j(1≤i,j≤n) 的约束下最大化∑ni=1xi+∑ni=1yi, 思路:采用最大权值完美匹配算法:但是现在这里是求最小权值完美匹配问题,所以只需要将权值取反最后在取反 ...

  6. ZOJ-2342 Roads 二分图最小权值覆盖

    题意:给定N个点,M条边,M >= N-1.已知M条边都有一个权值,已知前N-1边能构成一颗N个节点生成树,现问通过修改这些边的权值使得最小生成树为前N条边的最小改动总和为多少? 分析:由于计算 ...

  7. HDU 1853 HDU 3488【有向环最小权值覆盖问题 】最小费用最大流

    HDU 1853 & HDU 3488[有向环最小权值覆盖问题 ]带权二分图匹配 KM算法 In the kingdom of Henryy, there are N (2 <= N & ...

  8. poj3686(最小权值完美匹配)

    开始理解的有点简单了,也是看了其他的博客之后发现问题的: 题意:因为每一个物件都是受前一个物件的时间限制,所以假设某台机器加工了k个订单,那么用时为t1 + (t1 + t2) + (t1 + t2 ...

  9. 利用克鲁斯卡尔算法求最小生成树

    思路:最小生成树即为无向连通图G的一个子图如果是一颗包含G的所有顶点且权最小的树则称为最小生成树.克鲁斯卡尔算法的基本思想是以边为主导地位,始终选择当前可用的(所选的边不能构成回路)最小权值边.所以第 ...

最新文章

  1. Codis 3.2 集群搭建与测试
  2. 特征交互(Feature Interaction)及多项式特征(PolynomialFeatures)
  3. windows下jenkins常见问题填坑
  4. python arima模型_Python时间序列处理之ARIMA模型的使用讲解
  5. CVPR 2020 论文大盘点-文本图像篇
  6. 中国的城市看多了,贴贴美国的城市,肯定对你的视觉产生冲击
  7. outlook邮箱备份方法:
  8. jquery设置video的宽度_使用jQuery和CSS自定义HTML5 Video 控件 简单适用
  9. Style Report 培训开始啦!!
  10. 将本地的代码提交到github仓库
  11. seay代码审计mysql插件报错_Seay源代码审计系统2.1版本下载(附源码): 人人都是代码审计师...
  12. mysql必须记住的单词_如何真正记住英语单词?
  13. NDoc 用户指南(转)
  14. SQL相关概念与MYSQL下载安装卸载
  15. Cutting Bamboos
  16. 串口DCB定义,配置例程
  17. linux每个月清理命令,总结linux清理垃圾命令
  18. iOS 应用内购买基础教程 swift篇
  19. 混音师的混音之道|公开我学习混音的方法,真正的捷径|MZD Studios
  20. dnf选择服务器显示数字,DNF:遴选属性如何选择?两种方法精确找到最优解

热门文章

  1. iOS-Core-Animation-Advanced-Techniques(三)
  2. 正负数原码、反码、补码以及位运算
  3. 随着裁员浪潮滚滚而来,科技工作者的泡沫是否即将破灭?
  4. 4. DFT进阶——ATPG
  5. 学科实践活动感悟50字_社会实践活动的自我评价50字
  6. Python中如何进行代码换行?
  7. 第六周:整数转罗马数字
  8. WEB_BASIC---01 Web概述、HTML概述、文本处理、图像和超链接、表格、菜单
  9. postman Error: connect ECONNREFUSED xxx
  10. MFC 利用opencv实现视频播放