二分图最大权匹配——KM算法
前言
- 这东西虽然我早就学过了,但是最近才发现我以前学的是假的,心中感慨万千(雾),故作此篇。
简介
- 带权二分图:每条边都有权值的二分图
- 最大权匹配:使所选边权和最大的匹配
- KM算法,全称Kuhn-Munkres算法,是用于解决最大权匹配的一种算法。
- 根据我的理解,该算法算是一种基于贪心的松弛算法,它通过设置顶标将原问题转化为求一个完备匹配(完备匹配:匹配数=min(左部点数,右部点数))。
流程
- 设左部中点\(x\)的顶标\(wx_x\)、右部中点\(y\)的顶标\(wy_y\)。初始时\(wx_u=\max\{w_{u,v}\}\),\(wy_v=0\)。
- 我们扫一遍左部,每扫到一个\(x\)点,尝试增广,我们只能走满足条件\(wx_u+wy_v=w_{u,v}\)的边;这种边构成了原图的相等子图(不要问我为什么,它就叫这个名字)。我们增广失败,将访问过的点(包括增广失败的点)形成的树称为交错树,该树显然所有叶子都是\(x\)点。
- 接下来即是算法关键:我们为扩大相等子图(使当前的\(x\)尽量匹配上),修改所有交错树中的点的顶标,即将其中的\(x\)点顶标\(-d\),\(y\)点顶标\(+d\)。为保速度,\(d=\min\{wx_u+wy_v-w_{u,v}\}\)(\(u\)在交错树中,\(v\)不在交错树中)。
- 由于我们要尝试为左部\(n\)个点匹配,每次匹配最多增广\(n\)次(即最多要修改\(n\)次顶标,因为无法保证修改完一次顶标后就能扩大相等子图),每次增广是\(O(n+m)\)的,故此做法的复杂度应为\(O(n^2(n+m))\)。
某个优化
- 给每个\(y\)顶点一个“松弛量”函数\(slack\),每次开始找增广路时初始化为无穷大。在寻找增广路的过程中,检查边<i,j>时,如果它不在相等子图中,则让\(slack[j]\)变成原值与\(w_{i,j}\)的较小值。这样,在修改顶标时,取所有不在交错树中的\(y\)顶点的\(slack\)值中的最小值作为\(d\)值即可。但还要注意一点:修改顶标后,要把所有的不在交错树中的\(y\)顶点的\(slack\)值都减去\(d\)。
- 这个优化似乎是很有用,但并不能把KM优化到\(O(n^3)\)。这其实和原算法差不多,还是要为左部\(n\)个点匹配,每次匹配还是最多要增广\(n\)次,每次增广还是\(O(n+m)\)。如果是完全图,并且出题人稍微构造一下数据,依然是\(O(n^4)\)。
Code
bool dfs(int k) {
visx[k] = 1;
F(i, 1, n) {
if (!visy[i]) {
int t = A[k] + B[i] - Edge[k][i];
if (!t) {
visy[i] = 1;
if (!link[i] || dfs(link[i])) return link[i] = k;
} else slack[i] = min(slack[i], t);
}
}
return 0;
}
int KM() {
mem(link, 0);
F(i, 1, n) {
A[i] = -1e18, B[i] = 0;
F(j, 1, n)
A[i] = max(A[i], Edge[i][j]);
}
F(v, 1, n) {
int cnt = 0;
F(i, 1, n) slack[i] = 1e18;
while (1) {
mem(visx, 0), mem(visy, 0);
if (dfs(v)) break;
int d = 1e18;
F(i, 1, n) if (!visy[i]) d = min(d, slack[i]);
F(i, 1, n) if (visx[i]) A[i] -= d;
F(i, 1, n) if (visy[i]) B[i] += d; else slack[i] -= d;
}
}
Ans = 0;
F(i, 1, n) Ans += A[i] + B[i];
return Ans;
}
再次优化
- 先前的算法中,我们把大量时间浪费在 修改顶标-尝试增广 的操作上了。每次修改完顶标后,我们都要花至多\(O(n^2)\)的时间走先前已经走过的路。
- 但实际上,每次修改顶标后,我们可以确定一个\(y\)点可以被增广:那就是迫使我们修改顶标的那个\(y\)点。我们可以记录下它,并且下次增广就直接从它已连的\(x\)点增广(当然,如果它没有连\(x\)点,那就增广结束)。
- 这样,我们就把\(dfs\)的增广改为了一个类似\(bfs\)的东西。并且对于每个\(x\)点而言,每次修改顶标后不需要清空\(vis\)数组、增广时每个点、每条边至多被经过一次,故时间复杂度成功优化至\(O(n^2+nm)\)。
Code
void augment(int s)
{
mem(vis,0), mem(slack,63);
int y0,nxt=0,tm;
for(my[0]=s; vis[y0=nxt]=1,my[y0];)
{
int x=my[y0],d=INF;
fo(y,1,n)
if(!vis[y])
{
if((tm=wx[x]+wy[y]-w[x][y])<slack[y]) slack[y]=tm,pre[y]=y0;
if(slack[y]<d) d=slack[y],nxt=y;
}
if(d) fo(y,0,n) vis[y]?wx[my[y]]-=d,wy[y]+=d:slack[y]-=d;
}
for(int y; y0; y0=pre[y=y0],my[y]=my[y0]);
}
int KM()
{
mem(wy,0);
fo(i,1,n)
{
wx[i]=0;
fo(j,1,n)
{
if(wx[i]<w[i][j]) wx[i]=w[i][j];
if(wy[j]<w[i][j]) wy[j]=w[i][j];
}
my[i]=0;
}
fo(i,1,n*n) augment(i);
s=0;
fo(i,1,n*n) s+=wx[i]+wy[i];
return s;
}
小结
- 学算法时要带着脑子,莫被网上的博客骗了。
二分图最大权匹配——KM算法的更多相关文章
- HDU2255 奔小康赚大钱 —— 二分图最大权匹配 KM算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) ...
- Hdu2255 奔小康赚大钱(二分图最大权匹配KM算法)
奔小康赚大钱 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好 ...
- 二分图 最大权匹配 km算法
这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最 ...
- HDU3488 Tour —— 二分图最大权匹配 KM算法
题目链接:https://vjudge.net/problem/HDU-3488 Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit ...
- Uvalive 4043 Ants —— 二分图最大权匹配 KM算法
题目链接:https://vjudge.net/problem/UVALive-4043 题意: 给出n个白点和n个黑点的坐标, 要求用n条不相交的线段把他们连接起来,其中每条线段恰好连接一个白点和黑 ...
- hdu 2426 Interesting Housing Problem 最大权匹配KM算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2426 For any school, it is hard to find a feasible ac ...
- 网络流——二分图最优匹配KM算法
前言 其实这个东西只是为了把网络流的内容凑齐而写的(反正我是没有看到过这样子的题不知道田忌赛马算不算) 算法过程 我们令左边的点(其实二分图没有什么左右)为女生,右边的点为男生,那么: 为每一个女生定 ...
- “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 A noj 2073 FFF [ 二分图最大权匹配 || 最大费用最大流 ]
传送门 FFF 时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte总提交 : 145 测试通过 : 13 ...
- @noi.ac - 507@ 二分图最大权匹配
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...
随机推荐
- 每天一个Linux命令:locate(19)
locate locate命令 让使用者可以很快速的搜寻档案系统内是否有指定的档案.其方法是先建立一个包括系统内所有档案名称及路径的数据库,之后当寻找时就只需查询这个数据库,而不必实际深入档案系统之中 ...
- 接触python的第1天:测试hello world
在python3.8的平台可以输入了hello world, ide还能当做计算器 >>> print("hello world") hello world &g ...
- VLOOUP
VLOOKUP函数是Excel中的一个纵向查找函数 该函数的语法规则如下:VLOOKUP(lookup_value,table_array,col_index_num,range_lookup) 参数 ...
- 安装maven之后,cmd提示mvn不是内部命令的解决办法
1.maven的安装教程 下载地址为:http://maven.apache.org/download.cgi 进入此页面之后 点击下载,然后解压,我把目录名改为maven,目录结构如下图所示 下面我 ...
- 部署Jenkins完整记录
Jenkins通过脚本任务触发,实现代码的自动化分发,是CI持续化集成环境中不可缺少的一个环节.下面对Jenkins环境的部署做一记录.-------------------------------- ...
- 建站手册-浏览器信息:苹果 Safari 浏览器
ylbtech-建站手册-浏览器信息:苹果 Safari 浏览器 1.返回顶部 1. http://www.w3school.com.cn/browsers/browsers_safari.asp 2 ...
- iText例子
参考:http://itextpdf.com/book/examples.php daniel@daniel-mint ~/latex/linux/itext/daniel $ cat HelloWo ...
- HBase–RegionServer宕机恢复原理
Region Server宕机总述 HBase一个很大的特色是扩展性极其友好,可以通过简单地加机器实现集群规模的线性扩展,而且机器的配置并不需要太好,通过大量廉价机器代替价格昂贵的高性能机器.但也正因 ...
- RQNOJ PID331 家族
题目描述 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚.如果x,y是 ...
- 私有IP地址
私有IP地址: 在ABC三类网络中,如下三段网络地址为私有IP地址,如何人都可以自行在自己的局域网中使用这些IP地址. A类私有:10.0.0.1----10.255.255.254 B类私有:172 ...