二分图算法包括 匈牙利算法 与 KM算法。

匈牙利算法

在这里写上模板。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063

 #include<stdio.h>
#include<string.h>
#define mem(a, b) memset(a, b, sizeof(a)) int head[], cnt;
int k, m, n; //k为组合数,m为女生人数,n为男生人数
int used[], master[]; struct Edge
{
int to, next;
}edge[]; void add(int a, int b)
{
edge[++ cnt].to = b;
edge[cnt].next = head[a];
head[a] = cnt;
} int find(int x)
{
for(int i = head[x]; i != -; i = edge[i].next)
{
int to = edge[i].to;
if(used[to] == -)
{
used[to] = ;
if(master[to] == - || find(master[to]))
{
master[to] = x;
return ;
}
}
}
return ;
} int main()
{
int ans;
while(scanf("%d", &k)!=EOF)
{
if(k == )
break;
cnt = ans = ;
mem(head, -), mem(master, -);
scanf("%d%d", &m, &n);
for(int i = ; i <= k; i ++)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
for(int i = ; i <= m; i ++)
{
mem(used, -);
if(find(i))
ans ++;
}
printf("%d\n", ans);
}
return ;
}

KM算法

KM算法是用来解决带权问题的最大匹配. (用邻接矩阵实现, 首先因为带权的话, X部,Y部都有边,一般是稠密图,其次邻接表并不好实现)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255

 #include<stdio.h>
#include<string.h>
#define mem(a, b) memset(a, b, sizeof(a))
const int inf = 0x3f3f3f3f; int n, nx, ny;
int lx[], ly[];//x部点的值,y部点的值
int visx[], visy[];//标记x,y部的点是否在相等子图中,用于更新点的值
int slack[];//松弛量, 用于优化KM算法 优化后复杂度为 n^3
int goal[], weight[][]; int find(int x)//新增的x部的点
{
visx[x] = ;
for(int j = ; j <= ny; j ++)
{
if(!visy[j])
{
int t = lx[x] + ly[j] - weight[x][j]; //匹配到的标准是 x部 + y部点的值等于边权值
if(t == )
{
visy[j] = ;
if(goal[j] == - || find(goal[j]))
{
goal[j] = x;
return ;
}
}
else if(slack[j] > t)//没被匹配到的点记录最小slack
slack[j] = t;
}
}
return ;
} int km()
{
mem(ly, ); //y部的初始化为0
mem(lx, );
mem(goal, -);
for(int i = ; i <= nx; i ++)//x部点的值初始化为与y部相连的最大值
for(int j = ; j <= ny; j ++)
if(weight[i][j] > lx[i])
lx[i] = weight[i][j];
for(int i = ; i <= nx; i ++)
{//每次扩充一个点, 都要重新初始化y部的slack,因为需要在相等子图中找到最大的权值匹配
for(int j = ; j <= ny; j ++)
slack[j] = inf;
while()
{
mem(visx, );
mem(visy, );
if(find(i)) //如果当前子图可以匹配的到就跳出, 扩充下一个x部的点继续匹配
break;
//如果当前子图没匹配到,就用slack更新值再循环while寻找当前子图的最大权值匹配
int d = inf;
for(int j = ; j <= ny; j ++)
if(!visy[j] && d > slack[j])
d = slack[j];//找到一个最小的差值 在未尝试匹配的y部中找
for(int j = ; j <= ny; j ++)
if(!visy[j])
slack[j] -= d;
for(int j = ; j <= n; j ++)//参与匹配的点x部的减 ,y部的加
{
if(visy[j])
ly[j] += d;
if(visx[j])
lx[j] -= d;
}
}
}
int ans = ;
for(int j = ; j <= ny; j ++)
if(goal[j] != -)
ans += weight[goal[j]][j];
return ans;
} int main()
{
while(scanf("%d", &n)!=EOF)
{
nx = n, ny = n;
for(int i = ; i <= n; i ++)
for(int j = ; j <= n; j ++)
scanf("%d", &weight[i][j]);
int ans = km();
printf("%d\n", ans);
}
return ;
}

对于KM算法求最小匹配, 只需要在最大匹配的模板上改动几个地方即可,

在存图时将边权全记为负边权,那么会发现在对lx顶标记录最大值的时候实际上是绝对值最小的负值,也就是最小匹配了. 将lx[]数组初始化为-inf,然后对于最后的答案取负号就可以了.

二分图的最大匹配以及带权匹配【匈牙利算法+KM算法】的更多相关文章

  1. 奔小康赚大钱---hdu2255(最大带权匹配)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 带权匹配问题的模板: 运用KM算法: #include<stdio.h> #incl ...

  2. hdu3722Card Game(KM最大带权匹配)

    题目请戳这里 题目大意:给n个字符串,再给一个n的排列:p1,p2....pn.然后将第i个字符串贴到第pi个字符串后面,然后形成一个环.pi的首字符和第i个字符串的末尾字符就相邻,如果这2个字符相等 ...

  3. HDU2255 奔小康赚小钱钱(二分图-最大带权匹配)

    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子 ...

  4. POJ3565带权匹配——km算法

    题目:http://poj.org/problem?id=3565 神奇结论:当总边权最小时,任意两条边不相交! 转化为求二分图带权最小匹配. 可以用费用流做.但这里学一下km算法. https:// ...

  5. HDU - 2255 奔小康赚大钱(最大带权匹配)

     Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓, ...

  6. UVA - 10004 Bicoloring(判断二分图——交叉染色法 / 带权并查集)

    d.给定一个图,判断是不是二分图. s.可以交叉染色,就是二分图:否则,不是. 另外,此题中的图是强连通图,即任意两点可达,从而dfs方法从一个点出发就能遍历整个图了. 如果不能保证从一个点出发可以遍 ...

  7. 【二分图最大权完美匹配】【KM算法】【转】

    [文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] ...

  8. [C++]多源最短路径(带权有向图):【Floyd算法(动态规划法)】 VS n*Dijkstra算法(贪心算法)

    1 Floyd算法 1.1 解决问题/提出背景 多源最短路径(带权有向图中,求每一对顶点之间的最短路径) 方案一:弗洛伊德(Floyd算法)算法 算法思想:动态规划法 时间复杂度:O(n^3) 形式上 ...

  9. 运动员最佳匹配问题(km算法)

    洛谷传送门 带权二分图最大权完美匹配. 裸的km算法. 注意开long long. #include <cstdio> #include <cstring> #include ...

随机推荐

  1. Gradle 的项目导入到 IntelliJ 后子项目源代码不能导入

    在一个 Gradle 项目中,有若干子项目. 当 Gradle 到如后,子项目不能被 IntelliJ  识别代码. 如下图的这个代码就没有被自动识别. 这个有可能是因为你的这个子项目没有被添加到父项 ...

  2. Codevs 1574 广义斐波那契数列(矩阵乘法)

    1574 广义斐波那契数列 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 广义的斐波那契数列是指形如an=p*an-1+q* ...

  3. [转载]作为理工科学生,我们为什么要练就好的文笔?我们需要发blog来记录学习历程?

    文/JoeyChen 工程师该怎样才能突破自己的能力瓶颈?写 blog! 工程师该怎样精进自己在职涯上所需要的能力?写 blog! 工程师该怎样才能保持学习与成长的动能?写 blog! 工程师该怎样才 ...

  4. 【redis 学习系列】API的理解与使用(四)

    5.集合 集合(set)类型也是用来保存多个字符串元素,但是与列表不一样的是,集合中不允许有重复的元素,并且集合中的元素是无序的,不能通过索引下标获取元素. 如图2-22所示,集合user:1:fol ...

  5. 介绍 14 个 JavaScript 的框架和库

    Javascript 得到了众多的技术领导者的拥护和支持,其中一位就是 WordPress 的作者 Matt Mullenweg , 他表示 WordPress 开发者 应该学习 JavaScript ...

  6. 【零基础】一文读懂CPU(从二极管到超大规模集成电路)

    一.前言 我们都知道芯片,也知道芯片技术在21世纪是最重要的技术之一,但很少有人能知道芯片技术的一些细节,如芯片是如何构造的.为什么它可以运行程序.芯片又是如何被设计制造出来的等等.本文就尝试从最底层 ...

  7. Mybatis传递多个参数进行SQL查询的用法

    当只向xxxMapper.xml文件中传递一个参数时,可以简单的用“_parameter”来接收xxxMapper.java传递进来的参数,并代入查询. 但是,如果在xxxMapper.java文件中 ...

  8. 软件-设计-Adobe-Adobe XD:百科

    ylbtech-软件-设计-Adobe-Adobe XD:百科 创建线框.设计.创建原型.展示以及共享适用于 Web.移动设备和语音等的卓越体验 - 以上操作在一款应用程序中即可完成.XD 面向需要进 ...

  9. lsnrctl: .... cannot restore segment prot after reloc: Permission denied

    cannot restore segment prot after reloc: Permission denied Table of Contents 1. 错误信息 2. 解决方法 1 错误信息 ...

  10. Matlab获取文件夹下所有文件名并将数据按矩阵赋值给变量

    一.获取一个文件夹下所有文件名: fileFolder=fullfile('D:\MATLAB\bin\trc'); dirOutput=dir(fullfile(fileFolder,'*.trc' ...