二分图匹配(入门篇)
Posted bigyellowdog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分图匹配(入门篇)相关的知识,希望对你有一定的参考价值。
二分图匹配
- write by BigYellowDog
1. 什么是二分图?
有一个无向图,如果所有的点可以被所有的边分成两个点集。则说这个图为二分图
下图就是一个标准二分图:
2. 什么是二分图匹配?
现有一个二分图E,还有它的子集M。如果M中任意一条边都没有公共的端点。则M是一个“匹配”
- 如果一个匹配M’中边数是所有匹配中最多的,则说M’为“最大匹配”
如果匹配M中,所有点都得到了一一匹配,则说M是一个“完全匹配”
- 如上图(不用管最下面那一行字)。如果红黑线一起看的画,这个图就是一个二分图。如果只看红线的话,那么其所构成的图就是二分图的一个匹配。同时,它也是一个最大匹配(每个点都得到了一一匹配)。
3. 二分图的实际应用?
- 举个简单的例子。
- 一个学校需要分配教学任务,而且要使每科都尽量有老师教,每个老师都尽量有课教。
- 那么将老师抽象成一个点集,将课程抽象成另一个点集,进行二分图匹配算法,求出最大匹配。
4. 如何实现二分图匹配?
- 跑最大流dinic O( (nsqrt{m}) )
- 匈牙利算法 O (nm)
那么我这篇文章就只写匈牙利,因为
好写且好短。最大流这个坑以后我会填的(逃噢还有上面那么的复杂度分析n是点数,m是边数
匈牙利算法的流程图解网上大把多好文章。那么我就推荐两个我当时看的吧
5. 模版题(Luogu P3386)
- 贴出我的代码,里面有详细注释~
//阅读程序之前,请确保你阅读了我上面推荐的两个文章。
//因为本文视角是以“男女配对”看的(逃
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1005
using namespace std;
int n, m, q, ans;
int rel[maxn][maxn];
int mat[maxn];
bool vis[maxn];
bool dfs(int x)
{
for(int j = 1; j <= m; j++)
if(!vis[j] && rel[x][j])
//如果以前j这个女生跟x这个男生没有联系过并且x这个男生喜欢j这个女生
{
vis[j] = 1;
if(!mat[j] || dfs(mat[j]))
//如果这个女生没有人跟她配对
//或者她曾经配对成功的人可以跟另一个人私奔(那么这个女生不就没人配对了嘛)
{
mat[j] = x;
return 1;
}
}
return 0;
}
int main()
{
cin >> n >> m >> q;
for(int i = 1; i <= q; i++)
{
int u, v; cin >> u >> v;
if(v > m || u > n) continue;
rel[u][v] = 1;
/*
* 这里是建单向边。想想我们的配对过程,都是只关注一个点集
* 相对与另一个点集的情况
*/
}
for(int i = 1; i <= n; i++)
{
//vis数组是标记每个女生是否以前尝试跟i这个男生配对过。
//如果尝试配对过了,就不用再一次找她了,避免递归进入死循环
memset(vis, 0, sizeof(vis));
if(dfs(i)) ans++;
}
cout << ans;
return 0;
}
以上是关于二分图匹配(入门篇)的主要内容,如果未能解决你的问题,请参考以下文章
二分图匹配入门专题1H - Marriage Media light oj 1184二分图最大匹配