如果,将求二分图的最大匹配的所有匹配边的权重看做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算法的更多相关文章

  1. 图论(KM算法):COGS 290. [CTSC2008] 丘比特的烦恼

    290. [CTSC2008] 丘比特的烦恼 ★★★   输入文件:cupid.in   输出文件:cupid.out   简单对比 时间限制:1 s   内存限制:128 MB 随着社会的不断发展, ...

  2. 图论补档——KM算法+稳定婚姻问题

    突然发现考前复习图论的时候直接把 KM 和 稳定婚姻 给跳了--emmm 结果现在刷训练指南就疯狂补档.QAQ. KM算法--二分图最大带权匹配 提出问题 (不严谨定义,理解即可) 二分图 定义:将点 ...

  3. 图论(二分图,KM算法):HDU 3488 Tour

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  4. 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  5. 【原创】我的KM算法详解

    0.二分图 二分图的概念 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V, E)是一个无向图.如果顶点集V可分割为两个互不相交的子集X和Y,并且图中每条边连接的两个顶点一个在X中,另一个在Y ...

  6. KM算法详解[转]

    KM算法详解 原帖链接:http://www.cnblogs.com/zpfbuaa/p/7218607.html#_label0 阅读目录 二分图博客推荐 匈牙利算法步骤 匈牙利算法博客推荐 KM算 ...

  7. 训练指南 UVALive - 4043(二分图匹配 + KM算法)

    layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true ...

  8. 图论常用算法之一 POJ图论题集【转载】

    POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...

  9. 【POJ 2195】 Going Home(KM算法求最小权匹配)

    [POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submiss ...

随机推荐

  1. Less入门教程

    http://www.cnblogs.com/fsjohnhuang/p/4187675.html

  2. Scala学习笔记(四):从文件里读取文本行

    第一个版本: import scala.io.Source if(args.length>0){ for(line<-Source.fromFile(args(0)).getLines) ...

  3. MQTT 开源代理mosquitto的网络层封装相当sucks

    最近学习MQTT协议,选择了当前比较流行的MQTT Broker “mosquitto”,但是在阅读代码过程中发现其网络底层库封装的相当差劲. 对于MQTT协议的变长头长度的读取上,基本上采取每次一个 ...

  4. C++学习013多态

    何为多态 面向对象最要的特征之一就是多态,而纯虚函数是实现多态的主要方式.它可以提供一个通过用的接口,同样调用一个方法, 由于运算对象不同,方法也不同,这也就是所谓的动态绑定. #include &l ...

  5. APP功能性测试-4

    弱网络测试 使用fiddler模拟低速环境 使用fiddler抓取手机上某个应用的包 手机连接fiddler fiddler 代理地址127.0.0.1默认端口8888 只抓http协议(https, ...

  6. spring boot 打包问题

    一.jar包 1.maven build package 2.linux 下执行 java -jar & 命令后台运行,也可加入服务运行 二.war包 1.将pom中的<packagin ...

  7. 领扣[LeetCode]从零开始[使用C++][1,10]

    0.序 以后不做后端开发是不是就用不到C++了?真香.话不多说,我已经躺倒在第一题上了.不贴题目了,持续更新. 1.两数之和 原文:https://www.cnblogs.com/grandyang/ ...

  8. HDU 4782 Beautiful Soup (模拟+注意细节)

    思路就是用栈模拟,不用开实体的栈,直接记一个top指针就行. 说说这题的细节: 1.tag标签里的内容不要动,原样输出.比如<p aa bb cc>,就这样输出就行,不要删空格.题目中说了 ...

  9. 软件工程项目组Z.XML会议记录 2013/09/14

    软件工程项目组Z.XML会议记录 [例会时间]2013年9月14日星期六21:00-22:30 [例会形式]小组讨论 [例会地点]新主楼A1025 [例会主持]李孟 [会议记录]李孟 会议整体流程 一 ...

  10. Linux的常用目录学习笔记

    首先,先查看一下Linuxi的一级目录结构: ls: /:表示根目录,文件系统的入口,最高一级目录. bin和sbin:命令保存目录,bin是普通用户能,sbin是root用户用的:/bin存放着系统 ...