[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胜出,反 ...
随机推荐
- 转:Oracle下创建ASM磁盘总结
Oracle下创建ASM磁盘总结 文章转载:https://blog.csdn.net/okhymok/article/details/78791841?utm_source=blogxgwz1 2. ...
- MySQL执行计划的讲解
最近同事在执行线上执行一条MySQL的查询语句,数据的话在9000条左右,但使用左连接的时候查询速度大概在15秒左右~这速度确实是无法接受的~ 经过简单的修改,变为内连接的话,执行速度不到1秒. 下面 ...
- 第 十六 课 Map
Map 是一种无序的键值对的集合 var mymap map[string]string //先声明一个字典(map)名字叫做mymap,其key所对应的数据类型是string[字符串],value所 ...
- 基于人脸识别+IMDB-WIFI+Caffe的性别识别
本文用记录基于Caffe的人脸性别识别过程.基于imdb-wiki模型做finetune,imdb-wiki数据集合模型可从这里下载:https://data.vision.ee.ethz.ch/cv ...
- app自动更新(android)
更新插件代码:https://github.com/shixy/UpdateApp 来源:http://aspoems.iteye.com/blog/1897300 检查更新的时候,通过指定的URL获 ...
- vue axios 应用
vue安装axios cnpm install axios 安装成功后/项目/node_modules/目录下有axios文件夹 在package.json文件中devDependencies字段中添 ...
- 新增线下、APP、公众号多处入口,小程序会再火起来么?
现在,大多数互联网创业者最缺的是流量,第二缺的是钱.之前开发者们追捧小程序的重要原因就是在于认为这可能是下一个微信公众号体量的流量入口,因为大家都想从微信的8亿多用户中收获自己的一部分用户. 近期部分 ...
- JAVA基础知识总结11(异常)
异常: 就是不正常.程序在运行时出现的不正常情况.其实就是程序中出现的问题.这个问题按照面向对象思想进行描述,并封装成了对象.因为问题的产生有产生的原因.有问题的名称.有问题的描述等多个属性信息存在. ...
- android 自定义控件之事件
首先,继承需要扩展的VIEW,然后在里面添加一个自己的事件方法,例如, oniconclick(myinterface pinterface){ minterface = pinterface; } ...
- String类型的理解
引用:https://www.cnblogs.com/binyue/p/3862276.html java语言中: 变量除了八大基本数据类型(byte,short,int,long,boolean,f ...