博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KM算法入门
阅读量:6758 次
发布时间:2019-06-26

本文共 3705 字,大约阅读时间需要 12 分钟。

KM算法的基本概念:

看这个算法之前,最好先看下匈牙利算法,KM算法 是建立在匈牙利算法基础上实现的

对于这个算法最有误区的地方,个人感觉还是在  X 集合 -d  和 Y 集合 + d之后 还要进行

操作,再加上 深搜递归操作  ,理解容易产生误区,在这里我给出一组模板的测试数据来帮助初学者理解

注意观察: visx[],visy[],lx[],ly[],linky[],在调用中的变化:

3 4

0 0 2

0 1 6

1  1 7

2 1  14

2  2  3

模板:(O  ^ 4) 

#define M 505 #define inf 0x3fffffff bool sx[M], sy[M]; int match[M], w[M][M], n, m, d, lx[M], ly[M]; //n:左集元素个数; m:右集元素个数 void init () {
memset (w, 0, sizeof(w)); //不一定要,求最小值一般要初始化为负无穷! } bool dfs (int u) {
int v; sx[u] = true; for (v = 0; v < m; v++) {
if (!sy[v] && lx[u]+ly[v]==w[u][v]) {
sy[v] = true; if (match[v] == -1 || dfs (match[v])) {
match[v] = u; return true; } } } return false; } int KM () {
int i, j, k, sum = 0; memset (ly, 0, sizeof(ly)); for (i = 0; i < n; i++) {
lx[i] = -inf; for (j = 0; j < m; j++) if (lx[i] < w[i][j]) lx[i] = w[i][j]; } memset (match, -1, sizeof(match)); for (i = 0; i < n; i++) {
while (1) {
memset (sx, false, sizeof(sx)); memset (sy, false, sizeof(sy)); if (dfs (i)) break; d = inf; for (j = 0; j < n; j++) if (sx[j]) for (k = 0; k < m; k++) if (!sy[k]) d = min (d, lx[j]+ly[k]-w[j][k]); if (d == inf) //找不到完美匹配 return -1; for (j = 0; j < n; j++) if (sx[j]) lx[j] -= d; for (j = 0; j < m; j++) if (sy[j]) ly[j] += d; } } for (i = 0; i < m; i++) if (match[i] > -1) sum += w[match[i]][i]; return sum; }

改进后的模板(O^3)

/*其实在求最大 最小的时候只要用一个模板就行了,把边的权值去相反数即可得到另外一个.求结果的时候再去相反数即可*/ /*最大最小有一些地方不同。。*/ #include 
#include
#include
#include
//赤裸裸的模板啊。。 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++) if(linky[i]>-1) result += w[linky[i]][i]; return result; } int main() {
// freopen("g:/1.txt","r",stdin); while(true) {
scanf("%d%d",&nx,&ny); int a,b,c; while(scanf("%d%d%d",&a,&b,&c),a+b+c) {
w[a][b]=c; } printf("%d\n",KM()); break; } return 0; }

题目推荐:

第一题:hdu  2255   奔小康赚大钱

模板不解释

View Code

第二题:  hdu 1533  Going Home

 用 w[i][j] = -w[i][j]建图再套模板 求最大值   输出【-sum】

 

 

View Code

第三题:  hdu  1853  Cyclic Tour

注意是有向图,和重边的判断

 

View Code

第四题:hdu  3488  Tour

 

跟第三题几乎一样

 

View Code

第五题:hdu  3435  A new Graph Game

 

跟第三题代码基本上一样,只是要双向建图,也有重边

福大 AekdyCoin 出的题,好险的题啊,时间跑了 2000+ ;

 

View Code

第六题: hdu 2426  Interesting Housing Problem

注意 题目输入 |Vi| <= 10000  

左集是学生,右集是房子,w[i][j] < 0 不可匹配,最后无法完美匹配输出-1

 

View Code

第七题:hdu 2853  Assignment

 

思路:让原有匹配更有优势就可以了 
实现:所有权值扩大100倍,原有匹配【例如a匹配b】w[a][b]+ + 
设结果是res 
最大值:res/100 
至少改变个数:n - res%100  
这种处理比较有意思

 

View Code

第八题:hdu 3718  

 

题目求的是两字符串的最大相似度 
思路:因为第一个串的一种字母只能匹配第二个串的一种字母,所以可以转化为求 
【字母的最大匹配值/n】 注意输入 scanf--%s   不要用 %c%*c 

View Code

推荐题目链接:

转载地址:http://fjzeo.baihongyu.com/

你可能感兴趣的文章
人事面试100问题--巧妙应答
查看>>
【工具类】怎么进入阿里云docker仓库
查看>>
Ceres-Solver库入门
查看>>
悲惨而又丢人的创业经历:草根创业者含恨倾诉为什么失败
查看>>
理解WebKit和Chromium: WebKit, WebKit2, Chromium和Chrome介绍
查看>>
hanoi塔的递归算法
查看>>
C# 校验给定的ip地址是否合法
查看>>
lumen 登陆 注册 demo
查看>>
基于服务的并行系统的通讯方式探讨
查看>>
设计模式——观察者模式
查看>>
Python多线程 简明例子
查看>>
《地球上的星星》
查看>>
mysql数据库的主从同步,实现读写分离
查看>>
89 fcanf和fprintf
查看>>
javascript——自定义右键菜单
查看>>
求二叉树中相差最大的两个节点间的差值绝对值
查看>>
PHP 类名::class含义
查看>>
设计模式简介和分类,重点在总结
查看>>
数据库默认端口
查看>>
前端框架的区别,优缺点。
查看>>