匈牙利算法:

匈牙利算法几乎是二分图匹配的核心算法,除了二分图多重匹配外均可使用

匈牙利算法实际上就是一种网络流的思想,其核心就是寻找增广路。具体操作就是嗯。。拉郎配

匈牙利算法适用的场合:

  1. 二分图匹配
  2. 链上的匹配问题
  3. 一般图匹配等其他点的个数较小的匹配问题

举个以前写的博客的例子

通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(-_-||暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在让我们无视掉所有的单相思(好忧伤的感觉),你拥有的大概就是下面这样一张关系图,每一条连线都表示互有好感。

本着救人一命,胜造七级浮屠的原则,你想要尽可能地撮合更多的情侣,匈牙利算法的工作模式会教你这样做:

===============================================================================

一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,got it,连上一条蓝线

===============================================================================

:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,got it

===============================================================================

:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?

我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。

(黄色表示这条边被临时拆掉)

与1号男生相连的第二个女生是2号女生,但是2号女生也有主了,怎么办呢?我们再试着给2号女生的原配重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程)

此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去

2号男生可以找3号妹子~~~                  1号男生可以找2号妹子了~~~                3号男生可以找1号妹子

所以第三步最后的结果就是:

===============================================================================

: 接下来是4号男生,很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子,我们实在是无能为力了……香吉士同学走好。

===============================================================================

这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字

其原则大概是:有机会上,没机会创造机会也要上

算法步骤(基于二分图)

  1. 如果题目初始的时候给出的是一副一般图,我们可以利用拓扑染色(2-SAT、种类并查集等等)的方式来让他变成一个二分图。
  2. 将二分图分成X部和Y部,我们现在的做法是通过X部去匹配Y部;
  3. 我们从1~cnt_X的去枚举,如果没有被对面的Y给匹配过的,我们试着让他去匹配对应的有链接边的Y部,如果对面的Y部对应的点y是没有被匹配的,或者链接对应y的x是可以换一个没有被匹配过的点的,那么我们就让x去换,并且让我们现在枚举的1~cnt_X去链接对应的点
  4. 在算法上的优化,我们不难发现,如果目前的1~cnt_Y中的某个y在这一回合的匹配中是被利用过了的,那么也就是说,后面的点都是已经被操作过(且为false的),说明我们不用再继续往下跑了,所以可以利用一个vis标记来进行优化。在枚举x的1~cnt_X的同时,我们进入“腾”这个操作的时候,就是需要去对1~cnt_Y进行vis清空操作。

算法步骤(基于链)

  1. 链上的匈牙利算法的算法结构并不特殊,只是对于建边的时候需要慎重考虑。
  2. 它是在一条链上的匹配,我们当去寻求匹配对象的时候,我们要尽可能的先把前面的link[x]覆盖,不然当我们匹配到后面的时候却已经被覆盖了,不是最优解。
  3. 所以,我们的建边尽可能是要从后面的结点指向前面的结点,例如i -> j(i > j)
  4. 然后,我们1~N的枚举,当前的点一定是没有被匹配过的,因为操作3保证了。所以,我们直接去寻求匹配即可。

例题讲解(不按难度顺序排列)


Oil Skimming

HDU - 4185

这道题的精髓在于,i点和j点是成对匹配的。也就是说,当我们匹配上j点的时候,事实上,i点同时被j点匹配,所以我们一次操作的时候是需要赋值两次。

            link[v] = u;link[u] = v;

也就是这样。

My Code


Taxi Cab Scheme

HDU - 1350

这道题就是一道很模版的匈牙利算法在链上的操作了。

有N个人,他们在特定的时间(hour : minute)要从地点(a, b)前往地点(c, d),然后呢,我们如果说前一个人i的出租车可以开回来再接j这个人,那么他们就可以少叫一辆出租车了。现在,题目想知道最少的需求的出租车的个数。

图文讲解 + 代码


过山车

HDU - 2063

匈牙利算法的模板题,这里给出主要的结构。理清楚,我们在哪个位置要清空X的内容,在哪个位置是要去清空Y部的内容,我这里并没有去用拆点或者使用memset()来逃避这两个问题。

bool match(int u)
{for(int i=head[u], v; ~i; i=edge[i].nex){v = edge[i].to;if(vis[v]) continue;vis[v] = true;if(!link[v] || match(link[v])){link[v] = u;return true;}}return false;
}
inline int Hungery()
{int ans = 0;for(int i=1; i<=M; i++) link[i] = 0;for(int i=1; i<=N; i++){for(int j=1; j<=M; j++) vis[j] = false;if(match(i)) ans++;}return ans;
}

这两行是主要的代码,要仔细看清哪里用的是X,哪里用的是Y。(N对应X,M对应Y)


棋盘游戏

HDU - 1281

看着题意很复杂,但是我们可以简化一下。

不能横竖给交叉了,实际上指的是每个对应的x坐标对应唯一的y坐标,我们基于这点去对于二维平面进行匈牙利算法即可。复杂度是,其中的源于匈牙利算法的复杂度。

判断是否是重要结点,可以自己想想看。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 105;
int N, M, K, head[maxN], cnt, cn_X, cn_Y;
vector<pair<int, int>> vt;
struct Eddge
{int nex, to;Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN * maxN];
inline void addEddge(int u, int v)
{edge[cnt] = Eddge(head[u], v);head[u] = cnt++;
}
int link[maxN];
bool vis[maxN];
inline bool match(int u)
{for(int i=head[u], v; ~i; i=edge[i].nex){v = edge[i].to;if(u == cn_X && v == cn_Y) continue;if(vis[v]) continue;vis[v] = true;if(!link[v] || match(link[v])){link[v] = u;return true;}}return false;
}
inline int Hungery()
{int ans = 0;for(int i=1; i<=M; i++) link[i] = 0;for(int i=1; i<=N; i++){for(int j=1; j<=M; j++) vis[j] = false;if(match(i)) ans++;}return ans;
}
inline void init()
{cnt = 0; cn_X = cn_Y = 0; vt.clear();for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{int Cas = 0;while(scanf("%d%d%d", &N, &M, &K) != EOF){init();for(int i=1, u, v; i<=K; i++){scanf("%d%d", &u, &v);addEddge(u, v);vt.push_back(MP(u, v));}int const_ans = Hungery(), Important = 0;for(int i=0; i<K; i++){cn_X = vt[i].first; cn_Y = vt[i].second;if(Hungery() < const_ans) Important++;}printf("Board %d have %d important blanks for %d chessmen.\n", ++Cas, Important, const_ans);}return 0;
}

匈牙利算法【匹配问题】相关推荐

  1. 匈牙利算法学习笔记_Python代码

    学习华为上机测试题,遇见了下面题,很有意思,核心是匈牙利算法问题. 特此学习记录.资料均参考自网络. 匈牙利算法目的:找出两边最大的匹配的数量. 参考资料: https://blog.csdn.net ...

  2. 二分图匹配匈牙利算法DFS实现

    1 /*==================================================*\ 2 | 二分图匹配(匈牙利算法DFS 实现) 3 | INIT: g[][]邻接矩阵; ...

  3. 二分图匹配的匈牙利算法

    匈牙利算法,很绕,其实写起来也就一点点长度.. bool find(int a){int i,j;for(i=head[a];i;i=next[i]){j=to[i];//获得相邻的点if(!unab ...

  4. 利用匈牙利算法Hopcroft-Karp算法解决二分图中的最大二分匹配问题 例poj 1469 COURSES...

    首先介绍一下题意:已知,有N个学生和P门课程,每个学生可以选0门,1门或者多门课程,要求在N个学生中选出P个学生使得这P个学生与P门课程一一对应. 这个问题既可以利用最大流算法解决也可以用匈牙利算法解 ...

  5. 二分匹配(匈牙利算法)

    匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最 ...

  6. 二分图匹配之匈牙利算法

    二分图的基本概念: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于 ...

  7. [ACM_图论] The Perfect Stall 完美的牛栏(匈牙利算法、最大二分匹配)

    描述 农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术.不幸的是,由于工程问题,每个牛栏都不一样.第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们 ...

  8. 二分图匹配--匈牙利算法

    文章目录 二分图: 匹配 匈牙利算法 代码: 二分图: 二分图是一个无向图,点集分成子集X和Y,图中每一条边都是一边在X一边在Y 当且仅当无向图G的每一个回路次数都是偶数时(包括0),G就是一个二分图 ...

  9. 【匈牙利算法】【二分图匹配】【转载】趣写算法系列之--匈牙利算法

    转载自:http://blog.csdn.net/dark_scope/article/details/8880547 [书本上的算法往往讲得非常复杂,我和我的朋友计划用一些简单通俗的例子来描述算法的 ...

  10. 【HDU - 5943】Kingdom of Obsession(数论,素数间隔结论,构造,思维,匈牙利算法,匹配问题)

    题干: There is a kindom of obsession, so people in this kingdom do things very strictly. They name the ...

最新文章

  1. 微服务注册中心的选型和思考
  2. CUDA从入门到精通(零):写在前面
  3. 阿里巴巴云游戏平台荣获首届高新视频创新应用大赛一等奖
  4. 三层交换机有什么优势?
  5. 查询工资最低的3名员工的职工工号、姓名和收入_@打工人 | 关于工资条,这6个常识必须掌握,事关你的权益...
  6. HDU 6185 2017广西邀请赛:Covering(矩阵快速幂)
  7. 开课吧Java课堂:什么是流?如何运用字节流和字符流?
  8. 免费报名 | DataFunCon:自然语言处理论坛
  9. h5调用原生摄像头扫描二维码
  10. 用JavaScript+HTML实现双色球随机摇号效果
  11. html的个人简历边框,怎样制作简历模板边框
  12. deepspeech 1 (百度 2014 论文解读)
  13. 想要升级Big Sur 了?良心建议看看这个
  14. 12星座大全 ^__^
  15. 【THUSC2017】座位
  16. Excel 同一单元格显示不同颜色
  17. 【论文解读】NAACL 2021 对比自监督学习的上下文和一般句子表征:以篇章关系分析为例
  18. 右键删除或新增 Open Folder as Intellij IDEA Project
  19. 1.【Windows图标点击无反应修复
  20. 7款相见恨晚的资源网站,每个都百里挑一,送给正需要的你!

热门文章

  1. c语言99乘法表 倒三角形书写
  2. 多渠道门店如何进行会员管理和会员营销
  3. Ubuntu18.04 ibus 中文输入法崩溃解决实录
  4. 如何选择毕业设计的题目?
  5. 计算机专业实习日记,计算机专业实习日记精选
  6. 【论文阅读笔记】FCOS代码结合论文阅读
  7. 笔记本电脑计算机恢复出厂设置密码,笔记本电脑怎么恢复出厂设置?
  8. 【学习求职必备】微软亚洲研究院和它的10大AI黑科技
  9. 利用matlab函数创建数组
  10. Java NIO、BIO介绍