图论:KM算法
如果,将求二分图的最大匹配的所有匹配边的权重看做1
那么用匈牙利算法求二分图的最大匹配的问题也可以看成求二分图的最大权匹配
如果边权是特例,我们就要使用KM算法来做了
这个算法其实还是比较难的,会用就不错了,更不要说证明了
这里以HDU2255为例,这是一个裸题
在这个题目里面X和Y的size是一样的
然后我们稍微介绍一下这个算法(详细的以后再说吧,目前能力不够)
int n,nx,ny,ans;
int linker[maxn],lx[maxn],ly[maxn],slack[maxn],visx[maxn],visy[maxn];
int G[maxn][maxn];
linker记录的是与当前的下标节点(Y中)相连的X节点,lx和ly是节点顶标,slack是Y定点的松弛量函数
邻接矩阵存储
在这里面,如果有的边不存在,设置权重为0,这样图就可以近似看成一个全连接二分图
for(int i=;i<=nx;i++)
{
lx[i]=-INF;
for(int j=;j<=ny;j++)
{
if(G[i][j]>lx[i]) lx[i]=G[i][j];
}
}
首先初始化X中节点的节点顶标
就是对于每一个节点,看其所连接的所有的边,将最大权重设置为X节点顶标
然后呢,就是从每个节点开始进行DFS增广
根据情况修改可行顶标
for(int x=;x<=nx;x++)
{
for(int i=;i<=ny;i++) slack[i]=INF;
while()
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if(dfs(x)) break; //找到增广路,进入下一个点的增广
//如果失败,需要改变顶标使图中可行边数量增加
//在所有的增广路的x顶标中减去常数d
//在所有增广路的Y顶标中增加一个常数d
int d=INF;
for(int i=;i<=ny;i++)
if(!visy[i]&&d>slack[i])
d=slack[i];
for(int i=;i<=nx;i++)
if(visx[i]) lx[i]-=d;
for(int i=;i<=ny;i++)
if(visy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
然后DFS增广部分如下:
int dfs(int x)
{
visx[x]=;
for(int y=;y<=ny;y++)
{
if(visy[y]) continue;
int tmp=lx[x]+ly[y]-G[x][y];
if(tmp==)
{
visy[y]=;
if(linker[y]==-||dfs(linker[y]))
{linker[y]=x;return ;}
}
else if(slack[y]>tmp) slack[y]=tmp;
}
return ;
}
具体原理先鸽了,以后再说
然后给出完整的实现:
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=;
const int maxn=;
int n,nx,ny,ans;
int linker[maxn],lx[maxn],ly[maxn],slack[maxn],visx[maxn],visy[maxn];
int G[maxn][maxn];
int dfs(int x)
{
visx[x]=;
for(int y=;y<=ny;y++)
{
if(visy[y]) continue;
int tmp=lx[x]+ly[y]-G[x][y];
if(tmp==)
{
visy[y]=;
if(linker[y]==-||dfs(linker[y]))
{linker[y]=x;return ;}
}
else if(slack[y]>tmp) slack[y]=tmp;
}
return ;
}
int KM()
{
memset(linker,-,sizeof(linker));
memset(ly,,sizeof(ly));
for(int i=;i<=nx;i++)
{
lx[i]=-INF;
for(int j=;j<=ny;j++)
{
if(G[i][j]>lx[i]) lx[i]=G[i][j];
}
}
for(int x=;x<=nx;x++)
{
for(int i=;i<=ny;i++) slack[i]=INF;
while()
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if(dfs(x)) break; //找到增广路,进入下一个点的增广
//如果失败,需要改变顶标使图中可行边数量增加
//在所有的增广路的x顶标中减去常数d
//在所有增广路的Y顶标中增加一个常数d
int d=INF;
for(int i=;i<=ny;i++)
if(!visy[i]&&d>slack[i])
d=slack[i];
for(int i=;i<=nx;i++)
if(visx[i]) lx[i]-=d;
for(int i=;i<=ny;i++)
if(visy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
int res=;
for(int i=;i<=ny;i++)
if(linker[i]!=-)
res+=G[linker[i]][i];
return res; }
int main()
{
while(scanf("%d",&n)==)
{
nx=ny=n;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
scanf("%d",&G[i][j]);
ans=KM();
printf("%d\n",ans);
}
return ;
}
图论:KM算法的更多相关文章
- 图论(KM算法):COGS 290. [CTSC2008] 丘比特的烦恼
290. [CTSC2008] 丘比特的烦恼 ★★★ 输入文件:cupid.in 输出文件:cupid.out 简单对比 时间限制:1 s 内存限制:128 MB 随着社会的不断发展, ...
- 图论补档——KM算法+稳定婚姻问题
突然发现考前复习图论的时候直接把 KM 和 稳定婚姻 给跳了--emmm 结果现在刷训练指南就疯狂补档.QAQ. KM算法--二分图最大带权匹配 提出问题 (不严谨定义,理解即可) 二分图 定义:将点 ...
- 图论(二分图,KM算法):HDU 3488 Tour
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- 【原创】我的KM算法详解
0.二分图 二分图的概念 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V, E)是一个无向图.如果顶点集V可分割为两个互不相交的子集X和Y,并且图中每条边连接的两个顶点一个在X中,另一个在Y ...
- KM算法详解[转]
KM算法详解 原帖链接:http://www.cnblogs.com/zpfbuaa/p/7218607.html#_label0 阅读目录 二分图博客推荐 匈牙利算法步骤 匈牙利算法博客推荐 KM算 ...
- 训练指南 UVALive - 4043(二分图匹配 + KM算法)
layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true ...
- 图论常用算法之一 POJ图论题集【转载】
POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...
- 【POJ 2195】 Going Home(KM算法求最小权匹配)
[POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...
随机推荐
- 1176: [Balkan2007]Mokia
1176: [Balkan2007]Mokia 链接 分析 三维偏序问题,CDQ分治论文题. 代码 #include<bits/stdc++.h> using namespace std; ...
- LeetCode:11. ContainerWithWater(Medium)
原题链接:https://leetcode.com/problems/container-with-most-water/description/ 题目要求:给定n个非负整数a1,a2,...,an ...
- Android Stadio 指定文件打开类型
我们项目里面,有一个文件,叫做aaa.meta. 这个只是一个配置文件,里面是txt. 但是Android Stadio 不识别.怎么办? 设置如下图: 首先,打开Android stadio 的设置 ...
- 四大IO抽象类
四大IO抽象类 InputStream/OutputStream和Reader/writer类是所有IO流类的抽象父类,我们有必要简单了解一下这个四个抽象类的作用.然后,通过它们具体的子类熟悉相 ...
- Java中的IO流体系
Java为我们提供了多种多样的IO流,我们可以根据不同的功能及性能要求挑选合适的IO流,如图10-7所示,为Java中IO流类的体系. 注:这里只列出常用的类,详情可以参考JDK API文档.粗体标注 ...
- 利尔达NB-IOT模块对接移动onenet平台步骤
1. 首先登陆浙江移动onenet网站,http://openiot.zj.chinamobile.com/,进入右上角的开发者中心,然后才能看到创建产品 2. 填写产品的信息,其他信息按照个人实际填 ...
- (原)一段看似美丽的for循环,背后又隐藏着什么
之前很长一段时间,潜心修炼汇编,专门装了一个dos7,慢慢玩到win32汇编,再到linux的AT&A汇编,尝试写mbr的时候期间好几次把centos弄的开不了机,又莫名其妙的修好了,如今最大 ...
- Eclipse中JS文件红叉处理
使用新版本的Eclipse 或者 MyEclipse,项目中的 JS文件出现红叉,让人觉得项目中存在错误代码,给人的感觉很不爽. 记录一下去掉红叉的方法: 第1步: 打开工作空间中的项目找到项目的 . ...
- coia阻止事件上浮
1.阻止事件上浮 选择默认地址li 时 选中整个div使其为默认地址 此时点击编辑按钮也会触发选中默认事件 为事件添加event.stopPropagation();阻止事件上浮 2.js给页面inp ...
- CSP201604-1:折点计数
引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...