[SinGuLaRiTy] 二分图&匈牙利算法
【SinGuLaRiTY-1019】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.
二分图
二分图是图论中一种特殊的图形。顾名思义,二分图G可以被分为X、Y两个子图,在二分图中,没有任意一条连线的两个端点都属于X图或Y图,即每一条连线都贯穿连接着两个子图。二分图的一个重要等价定义是:不含有「含奇数条边的环」的图。
如图-1所描绘的图像就是一个二分图,而图-2就不是一个二分图。

图-1 图-2
匹配
在图论中,一个匹配是一个边的集合,其中任意两条边都没有公共顶点。
如图-3中的红色边就是图-1的一种匹配(显然,匹配可能不止一种)

图-3
相关的定义还有匹配点、匹配边、未匹配点、非匹配边,它们的含义也就显而易见了。
最大匹配
一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 -4 是一个最大匹配。
完美匹配
如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。图 -4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。

图-4
下面我们借用一个例子来看看这两种匹配的区别:(Tips: 这个例子摘自其它博客,但确实很形象)
如下图所示,如果在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢呢?图论中,这就是完美匹配问题。如果换一个说法:最多有多少互相喜欢的男孩/女孩可以配对儿?这就是最大匹配问题。

匈牙利算法的相关概念
交替路
从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路 (比较形象)。
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路。例如,图- 5 中的一条增广路如图 -6 所示(图中的匹配点均用红色标出)

图-5 图-6
增广路有一个重要特点:非匹配边比匹配边多一条。因此,研究增广路的意义是改进匹配,只要把增广路中的匹配边和非匹配边的身份交换即可。由于中间的匹配节点不存在其他相连的匹配边,所以这样做不会破坏匹配的性质。交换后,图中的匹配边数目比原来多了 1 条。
我们可以通过不停地找增广路来增加匹配中的匹配边和匹配点。找不到增广路时,达到最大匹配(这是增广路定理)。匈牙利算法正是这么做的。
匈牙利树
(Tips: 这一段的图画起来实在是太复杂了,故复制了pi9nc的图片)
匈牙利树一般由 BFS 构造(类似于 BFS 树)。从一个未匹配点出发运行 BFS(唯一的限制是,必须走交替路),直到不能再扩展为止。例如,由图Fig.7,可以得到如Fig.8 的一棵 BFS 树:

这棵树存在一个叶子节点为非匹配点(7 号),但是匈牙利树要求所有叶子节点均为匹配点,因此这不是一棵匈牙利树。如果原图中根本不含 7 号节点,那么从 2 号节点出发就会得到一棵匈牙利树。这种情况如Fig.9 所示(顺便说一句,Fig.8 中根节点 2 到非匹配叶子节点 7 显然是一条增广路,沿这条增广路扩充后将得到一个完美匹配)。
匈牙利算法的思路
用增广路求最大匹配(称作匈牙利算法,匈牙利数学家Edmonds于1965年提出) 算法轮廓:
(1)置M为空
(2)找出一条增广路径P,通过取反操作获得更大的匹配M’代替M
(3)重复(2)操作直到找不出增广路径为止
<伪代码>
bool dfs(int k) //寻找从k出发的对应项的可增广路
{
while (从邻接表中列举k能关联到顶点j)
{
if (j不在增广路上)
{
把j加入增广路;
if (j是未盖点 或者 从j的对应项出发有可增广路)
{
修改j的对应项为k;
从k的对应项有可增广路,返回true;
}
}
}
从k的对应项出没有可增广路,返回false;
}
int hungary() //匈牙利算法主函数
{
for i = to n do//左部顶点数
{
清标志数组//右部
if (从I有可增广路)
匹配数++;
}
return 匹配数;
}
/*
[说明]
算法的核心是 dfs(int k)函数,它的作用是:
寻找顶点k可能匹配的顶点。对于每个可以与k匹配的顶点j,假如它未被匹配,可以直接使用j与k匹配;
假如j已与某顶点x匹配,那么只需调用dfs(x)来求证x是否可以与其它顶点匹配,如果返回true的话,仍可以使j与k匹配,这就是一次dfs;
每次dfs时,要标记访问到的顶点(visit[j]=true),以防死循环和重复计算;
每次dfs开始前所有的顶点都是未标记的。 主过程只需对每个左侧的顶点调用dfs,如果返回一次true,就对最大匹配数加一;一个简单的循环就求出了最大匹配的数目。
*/
实现代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<iostream> #define MAXN 110 //最大顶点数 using namespace std; bool Map[MAXN][MAXN]; //二分图结构-邻接矩阵存储,有向图
bool visit[MAXN]; //标志数组,标记Y集合中的 i 元素是否被检测到过
int match[MAXN]; //存储匹配的方案,Y集合中的 i 元素匹配 X 中的某个元素
int n,m; //n, m 分别为X集合与Y集合的顶点数 bool dfs(int k)
{
int i,t;
for(i=;i<=m;i++)
if(Map[k][i]&&!visit[i])
{
visit[i]=true;
if( match[i]==||dfs(match[i]))
{
match[i]=k;
return true;
}
}
return false;
}
int hungary()
{
int i,ans;
ans=;
for(i=;i<=m;i++)
match[i]=;
for(i=;i<=n;i++)
{
memset(visit,,sizeof(visit));
if(dfs(i))
ans++;
}
return ans;
}
int main()
{
int i,j,k;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
for(j=;j<=m;j++)
{
scanf("%d",&k);
if(k==)
Map[i][j]=true;
else
Map[i][j]=false;
}
printf("%d",hungary());
return ;
}
Time: 2017-07-05
[SinGuLaRiTy] 二分图&匈牙利算法的更多相关文章
- hiho1122_二分图匈牙利算法
题目 给定一个图的N个节点和节点之间的M条边,数据保证该图可以构成一个二分图.求该二分图最大匹配. 题目链接:二分图最大匹配 首先通过染色法,将图的N个节点分成两个部分:然后通过匈牙利算法求二 ...
- hdu-1150(二分图+匈牙利算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1150 思路:题目中给出两个机器A,B:给出k个任务,每个任务可以由A的x状态或者B的y状态来完成. 完 ...
- POJ 3020 Antenna Placement(二分图 匈牙利算法)
题目网址: http://poj.org/problem?id=3020 题意: 用椭圆形去覆盖给出所有环(即图上的小圆点),有两种类型的椭圆形,左右朝向和上下朝向的,一个椭圆形最多可以覆盖相邻的两 ...
- cogs 886. [USACO 4.2] 完美的牛栏 二分图 匈牙利算法
886. [USACO 4.2] 完美的牛栏 ★★☆ 输入文件:stall4.in 输出文件:stall4.out 简单对比时间限制:1 s 内存限制:128 MB USACO/sta ...
- POJ 3041 Asteroids(二分图 && 匈牙利算法 && 最小点覆盖)
嗯... 题目链接:http://poj.org/problem?id=3041 这道题的思想比较奇特: 把x坐标.y坐标分别看成是二分图两边的点,如果(x,y)上有行星,则将(x,y)之间连一条边, ...
- HDU - 2444 二分图最大匹配 之 判断二分图+匈牙利算法
题意:第一行给出数字n个学生,m条关系,关系表示a与b认识,判断给定数据是否可以构成二分图,如果可以,要两个互相认识的人住一个房间,问最大匹配数(也就是房间需要的最小数量) 思路:要看是否可以构成二分 ...
- POJ1325机器重启次数——二分图匈牙利算法模板
题目:http://poj.org/problem?id=1325 求最小点覆盖.输出最大匹配数就行,结果略复杂地弄了. 注意由题可知 可以直接把与0有关的边删掉.不过亲测不删0而计数时不计0就会WA ...
- UESTC 919 SOUND OF DESTINY --二分图最大匹配+匈牙利算法
二分图最大匹配的匈牙利算法模板题. 由题目易知,需求二分图的最大匹配数,采取匈牙利算法,并采用邻接表来存储边,用邻接矩阵会超时,因为邻接表复杂度O(nm),而邻接矩阵最坏情况下复杂度可达O(n^3). ...
- HDU5090--Game with Pearls 二分图匹配 (匈牙利算法)
题意:给N个容器,每个容器里有一定数目的珍珠,现在Jerry开始在管子上面再放一些珍珠,放上的珍珠数必须是K的倍数,可以不放.最后将容器排序,如果可以做到第i个容器上面有i个珍珠,则Jerry胜出,反 ...
随机推荐
- 把python2.6升级到python2.7(同样适用于把python2升级到python3)
在启用https过程中,在生成CSR(证书请求文件)时,报错了,说python2.6已被python团队抛弃了,所以升级python到2.7 话不多说,直接上代码: 步骤1:下载python2.7.1 ...
- (转)C# -- 扩展方法的应用(Extension Methods)
本文转载自:http://blog.csdn.net/zxz414644665/article/details/9793205 当你有下面这样一个需求的时候,扩展方法就会起到作用:在项目中,类A需要添 ...
- calc PI
https://en.wikipedia.org/wiki/Pi code https://github.com/HHS-IntroProgramming/Calculate-Pi https://g ...
- C++11 引用叠加规则和模板参数类型推导规则
http://zm8.sm-img2.com/?src=http%3A%2F%2F***%2FArticle%2F38320&uid=57422b713ac761e653af7b327bfd9 ...
- C#实现有向无环图(DAG)拓扑排序
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在 ...
- FMX 模态窗体
FMX 模态窗体 dlg := TForm2.Create(nil); dlg.ShowModal(procedure(ModalResult: TModalResult) begin ...
- 用java代码解决10元喝多少瓶汽水的问题
问题:汽水2元一瓶,四个盖子换一瓶,两个空瓶一瓶,问10元可以喝几瓶?(不许借别人空瓶或瓶盖,但可以先喝汽水再付空酒瓶或瓶盖) 最近同事让笔者看了一道脑筋急转弯的数学题,当然不是很难,只要会加减法应该 ...
- MySQL建立一个连接工具类
public class DBUtil { public static Connection getConn() { Connection conn = null; try { Class.forNa ...
- 学习计划Python-转载
作者:闲谈后链接:https://www.zhihu.com/question/29775447/answer/145395619来源:知乎著作权归作者所有,转载请联系作者获得授权. 不过需要说明的是 ...
- 地图投影的N种姿势(转载)
转载地址:http://blog.sina.com.cn/s/blog_517eed9f0102w4rm.html 一篇题为<我们看到的地图一直都错得离谱……>的文章在朋友圈里莫名流行起来 ...