如果,将求二分图的最大匹配的所有匹配边的权重看做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. 2002: [Hnoi2010]Bounce 弹飞绵羊

    2002: [Hnoi2010]Bounce 弹飞绵羊 https://www.lydsy.com/JudgeOnline/problem.php?id=2002 分析: 绵羊在弹飞的路径中相当于一棵 ...

  2. 3122 奶牛代理商 VIII(状压dp)

    3122 奶牛代理商 VIII  时间限制: 3 s  空间限制: 256000 KB  题目等级 : 大师 Master     题目描述 Description 小徐是USACO中国区的奶牛代理商 ...

  3. 「日常训练」Phone Numbers (CFR466D2C)

    题意(Codeforces 940C) 给定一字符串,求比它字典序大的字符串.限定其长度,并且只能用原串的字母. 分析 考虑原串长度lorigin与给定的长度lgiven.若给定长度大于原串长度,直接 ...

  4. Ubuntu 添加中文字体

    查看系统类型 cat /proc/version 查看中文字体 fc-list :lang=zh-cn 安装字体 sudo apt install -y --force-yes --no-instal ...

  5. 面向对象 公有私有 property classmethod staticmethod

    接口类(抽象类)--------就是一种规范 面向对象的私有与公有 对于每一个类的成员而言都有两种形式: 公有成员,在任何地方都能访问 私有成员,只有在类的内部才能方法 私有成员和公有成员的访问限制不 ...

  6. 第一周 Introduction

    欢迎 欢迎来到这门关于机器学习的免费网络课程,机器学习是近年来最激动人心的技术之一,在这门课中,你不仅可以了解机器学习的原理,更有机会进行实践操作,并且亲自运用所学的算法. 每天你都可能在不知不觉中使 ...

  7. 在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现

    现在的深度学习框架一般都是基于 Python 来实现,构建.训练.保存和调用模型都可以很容易地在 Python 下完成.但有时候,我们在实际应用这些模型的时候可能需要在其他编程语言下进行,本文将通过直 ...

  8. Spring定时器调用Hibernate方法无法获得SessionFactory的解决办法

    由于在Spring定时器中无法通过注解的方式获取bean,因此需要通过原生的方式获取.获取session的方式如下: WebApplicationContext wac = ContextLoader ...

  9. DPDK 网卡RSS(receive side scaling)简介

    网卡RSS(receive side scaling)简介 RSS是一种网卡驱动技术,能让多核系统中跨多个处理器的网络收包处理能力高效能分配.注意:由于同一个核的处理器超线程共享同一个执行引擎,这个效 ...

  10. C#数据库连接问题

    最近在看C#,今天下午刚开始接触C#的数据库连接,SQL Server2008,问题如图:在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名 ...