如果,将求二分图的最大匹配的所有匹配边的权重看做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. 剁了xp,醉了win7

    装完win7,安装各种软件完毕,重启,然并卵.  cpu,内存飙升!! svchost.exe这个进程内存发疯了一样往上飙升 从 几十兆  到占用1个多G, 纳尼, 总共物理内存才2G. ╮(╯▽╰) ...

  2. 对mysqlbinlog日志进行操作的总结包括 启用,过期自动删除

    操作命令: show binlog events in 'binlog.000016' limit 10; reset master 删除所有的二进制日志 flush logs  产生一个新的binl ...

  3. Android2.2以上的版本HttpURLConnection.getContentLength()获取的size跟下载下来的file的legth不相等

    2.2以上的版本下载网络资源不完整无法更新.HttpURLConnection.getContentLength()获取的size跟下载下来的file的legth不等. 原因是:HttpURLConn ...

  4. 「暑期训练」「Brute Force」 Restoring Painting (CFR353D2B)

    题意 给定一定条件,问符合的矩阵有几种. 分析 见了鬼了,这破题谁加的brute force的标签,素质极差.因为范围是1e5,那你平方(枚举算法)的复杂度必然爆. 然后你就会思考其中奥妙无穷的数学规 ...

  5. zabbix 通过key(键值)获取信息

    在agent端进行修改264行,例如: UserParameter=get.os.type,head -1 /etc/issue 保存重启agent 验证 zabbix_get -s IP -k ge ...

  6. 剑指offer-用两个栈实现队列05

    class Solution: def __init__(self): self.stackpush=[] self.stackpop=[] def push(self, node): # write ...

  7. 编译 TensorFlow 的 C/C++ 接口

    TensorFlow 的 Python 接口由于其方便性和实用性而大受欢迎,但实际应用中我们可能还需要其它编程语言的接口,本文将介绍如何编译 TensorFlow 的 C/C++ 接口. 安装环境: ...

  8. POJ 1015 Jury Compromise (动态规划)

    dp[i][j]代表选了i个人,D(J)-P(J)的值为j的状态下,D(J)+P(J)的最大和. #include <cstdio> #include <cstring> #i ...

  9. Servlet入门(2)

    1.url_pattern匹配模式 2.servlet生命周期 3.servlet线程问题 一.url_pattern 1.定义: 当浏览器发起一个url请求后,该请求发送到servlet容器的时候, ...

  10. JAVA课程设计 俄罗斯方块

    俄罗斯方块 可实现功能 1.账号管理:登录.注册 2.游戏实现:移动.旋转.消除方块统计得分.暂停游戏.暂停后继续游戏.此轮游戏未结束开启新一轮游戏.游戏未结束退出游戏. 3.排行榜:按分数排名.按局 ...