学习心得 - 算法 - 匈牙利(增广路算法)
整个二分图,就是一个不断修改的 Romatic 史。
情人节特辑?或许是吧。
什么是二分图最大匹配
左边 \(n\) 个点,右边 \(m\) 个点,相连 \(e\) 条边。
我们要让左右 ♥ 两 ♥ 两 ♥ 匹 ♥ 配 ♥,求最大 ♥ 匹 ♥ 配 ♥ 对 ♥ 数。
算 ♥ 法 ♥ 演 ♥ 示
在这里我们使用匈牙利算法。
首先我们需要一些人。

左边是 ♥ 男 ♥ 孩 ♥ 纸。
右边是 ♥ 女 ♥ 孩 ♥ 纸。
我们把此题的样例 \(2\) 画下来就是这样的。
注意到我们可以成全最多 \(2\) 对:

还有其他很多匹配方法,但是答案为 \(2\)。
我们想如何匹配?
我们考虑枚举左侧节点,再通过搜索搜出他的 npy 匹配节点。
我们通过图片来理解一下。
男 \(1\) 号

我们枚举 NPY 时可以枚举到女 \(1\) 号和女 \(2\) 号。
女 \(1\) 号
她还没有 NPY,所以我们将女 \(1\) 号的 NPY 设为男 \(1\) 号。我们定 \(f_1=1\),设置女 \(1\) 号的 NPY,同时设置 \(npy_1=1\),代表这个点找到了 NPY。
女 \(2\) 号
男 \(1\) 号已经有 NPY 了,所以我们不修改女 \(2\) 的状态。
记录答案
男 \(1\) 号找到了 NPY,匹配成功记录答案!
男 \(2\) 号

孤独的男 \(2\) 号无法匹配 NPY,匹配失败 T^T。
男 \(3\) 号
男 \(\sout{1}\) 号的强力竞争者!

女 \(1\) 号
已经被男 \(1\) 占有了!
我们先让男 \(3\) 抢先占有女 \(1\),\(npy_1=3\)。
接着,让男 \(1\) 做出抉择:男 \(1\) 还可以选女 \(2\)!
太好了,我们的匹配情况就变成了:
女 \(2\) 号
已经被男 \(1\) 号占有了!而且男 \(3\) 已有 NPY,不处。
记录答案
男 \(3\) 号找到了 NPY,匹配成功记录答案!
男 \(4\) 号
啥也不是。。。

女 \(2\) 号
男 \(4\) 发现女 \(2\) 已有 NPY 男 \(1\)。
无语。最终没有 NPY T^T
最终状态

匹配对数 \(2\)。
匈牙利算法
我们刚刚做的匹配操作,就是匈牙利算法。
家长:建议让 OI 不要再伤害青少年之匈牙利算法。
考虑使用 \(npy\) 表示女方的 NPY,然后枚举男方。
- 首先枚举占有女 \(v\) 号。
- 然后判断是否能成功 ♥ 与 ♥ 女 ♥ \(v\) ♥ 号 ♥ 配 ♥ 对 ♥。
细说配对。- 要是 \(npy_v=0\),那好皆大欢喜。
- 否则是遇上情敌了,以出题人给的强悍力量让原有 \(npy_v\) 考虑换 NPY,要是换不了那么占有失败,否则匹配成功。
- 统计一下有多少次匹配成功即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
int n,m,ee,U,V,npy[N],ncnt;
int found[N];
bool e[N][N];
bool dfs(int p){
for(int v=1;v<=m;v++)if(e[p][v]&&!npy[v]){
npy[v]=1;
if(!found[v]||dfs(found[v])){
found[v]=p;
return 1;
}
}
return 0;
}
int main(){
cin>>n>>m>>ee;
for(int i=1;i<=ee;i++){
cin>>U>>V;
e[U][V]=1;
}
for(int i=1;i<=n;i++){
memset(npy,0,sizeof(npy));
if(dfs(i))++ncnt;
}
cout<<ncnt;
return 0;
}
最后,祝愿广大 OIer 早日找到 NPY
(虽然这不可能——From Anguei

浙公网安备 33010602011771号