二分匹配的匈牙利算法 51NOD2006(文末)
来源:互联网 发布:简单的单片机设计作品 编辑:程序博客网 时间:2024/05/20 12:50
参考及图片来源:https://comzyh.com/blog/archives/148/
二分图:简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。准确地说:把一个图的顶点划分为两个不相交集
(即 如果题目中的 元素 能够 被 分成 两组不同的点集,就是可以用二分图表示的,每个组内的点互不相连,边只在两个点集间产生 )
如下图:
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。下图 是一个最大匹配,它包含 4 条匹配边。
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。上图 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。
求二分图最大匹配可以用最大流(Maximal Flow) (更复杂) 或者匈牙利算法(Hungarian Algorithm)
下面介绍匈牙利算法:
http://www.nocow.cn/index.php/Translate:USACO/stall4
以此题为例:
算法最基本轮廓:
- 置边集M为空(初始化,谁和谁都没连着)
- 选择一个新的原点寻找增广路
- 重复(2)操作直到找不出增广路径为止(2,3步骤构成一个循环)
模拟步骤如上图所示(过于详细,大牛请无视):
- 初始化(清空)
- 从A所连接的点中找到一个未在本次循环中搜索过的点2,并将2标记为搜索过,因为2没有被连接过,匹配A2
- 结束上次,开始新的循环,将所有点标记为未搜索过
- 搜索B,找到一个未在本次循环中搜索过的点2,标记为搜索过
- 发现2被匹配过,从2的父亲A寻找增广路,递归搜索A{从A所连接的点中找到一个未在本次循环中搜索过的点5(1已经标记为绿色),将5标记为搜索过,因为5没有被匹配过,匹配A5}找到增广路(此处为增广路的关键)
- 结束上次,开始新的循环,将所有点标记为未搜索过
- 搜索C,找到一个未在本次循环中搜索过的点1,并将1标记为搜索过,发现1未被匹配过,匹配C1
- 结束上次,开始新的循环,将所有点标记为未搜索过
- 搜索D,找到一个未在本次循环中搜索过的点1,并将1标记为搜索过,发现1被匹配过,递归搜索1的源C寻找增广路
- {搜索C,找到一个未在本次循环中搜索过的点5,标记为搜索过,发现5被匹配,进一步返现没有其他可连接点,返回找不到增广路}返回第9步
- 搜索D,找到一个未在本次循环中搜索过的点2,发现2被匹配,递归搜索2的源B寻找增广路
- {搜索B,找到一个未在本次循环中搜索过的点3,并将3标记为搜索过,发现3未被匹配,匹配B3返回找到}既然B另寻新欢,匹配D2
- 结束上次,开始新的循环,将所有点标记为未搜索过,递归搜索D寻找增广路
- 搜索E,找到一个未在本次循环中搜索过的点2,并将2标记为搜索过,发现2被匹配过,递归搜索2的源D寻找增广路
- {搜索D,发现1,5均被匹配过,返回找不到增广路}
- E无其他可连接节点,放弃E,E后无后续节点,已经遍历A-E,结束算法
例题: 51NOD 2006 (看了code就明白)
https://www.51nod.com/onlineJudge/questionCode.html#problemId=2006¬iceId=293729
#include <bits/stdc++.h>using namespace std;const int AX = 200;int g[AX][AX];int linker[AX];bool used[AX];int m,n;bool dfs( int u ){int v;for( v = m+1 ; v <= n ;v ++ ){ if( g[u][v] && !used[v] ){ //如果u 和 v 能够相连 并且 点未被访问used[v] = true;//标记点if( linker[v] == -1 || dfs(linker[v]) ){ //如果点没有连接边 或者 已连接 但回溯 到其相连的点发现那个点仍能链接别的点,就将这个点的边变换linker[v] = u; //链接新边return true; //返回真,匹配成功}}}return false; }int xyl(){int res = 0;int u;memset(linker,-1,sizeof(linker)); //首先各边初始化为未连接for( u = 1 ; u <= m ; u++ ){ memset(used,0,sizeof(used)); //每次都将点设置为为访问过if( dfs(u) ) res++; //用DFS查找匹配}return res;}int main(){ios_base::sync_with_stdio(false);cin.tie(0);cin>>m>>n;int x,y;while( cin>>x>>y && x != -1 && y != -1 ){g[x][y] = 1; //加入题目给出的边}int ans = xyl(); //调用匈牙利算法if( ans == 0 ) printf("No Solution!\n");else cout<<ans<<endl;return 0;}
- 二分匹配的匈牙利算法 51NOD2006(文末)
- 51nod2006 飞行员配对(二分图最大匹配)匈牙利算法
- 二分匹配(匈牙利算法)
- (算法)二分图的最大匹配(匈牙利算法)
- 二分匹配 ---- 匈牙利算法
- 二分匹配,匈牙利算法
- 二分匹配 匈牙利算法
- 二分图的最大匹配(匈牙利算法)
- 二分图的最大匹配(匈牙利算法)
- 二分图的最大匹配(匈牙利算法)
- 二分图的最大匹配 (匈牙利算法)
- 二分图的最大匹配(匈牙利算法)
- 二分图匹配匈牙利算法([ZJOI2009]假期的宿舍)
- 51NOD2006 飞行员配对(二分图最大匹配)
- 51nod2006 飞行员配对(二分图最大匹配)
- 匈牙利算法 (二分图的最大匹配)
- [zz] 二分图匹配的匈牙利算法
- 二分图最大匹配的匈牙利算法
- SQL TOP子句
- java web定时任务调度总结
- JDFZD3总结
- 【深度学习】【caffe实用工具5】笔记27 windows下SSD网络中的get_image_size工具的使用
- 404. Sum of Left Leaves
- 二分匹配的匈牙利算法 51NOD2006(文末)
- cocos2d-x 3.x之动作
- UE4-Android-APK大小
- java内存区域
- HIVE以及OOZIE添加第三方JAR包的方法
- Linux Man命令
- 表格nth-child设置行列样式
- 大话AOP与Android的爱恨情仇
- 微信随机红包数详解和算法代码