概念
匈牙利算法
这个算法的过程是这样的;
枚举每一个左部点 u u u ,然后枚举该左部点连出的边;
对于一个右部点 v v v,如果它没有被先前的左部点匹配,那么直接将 u u u 匹配 v v v;
否则尝试让 v v v 的之前配对的左部点去匹配其他右部点,如果之前配对的左部点匹配到了其他点,那么将 u u u 匹配 v v v,否则 u u u 失配。
我的个人理解
二分图最大匹配,就是一群人,喜欢一类东西,然后求最多满足能满足多少人的问题。
以下是匈牙利算法的个人理解版本…
一个人可以喜欢多样东西 也可以只喜欢一个东西 但是最终他只能拿一个东西
如果一个东西没有被人选 那么它就可以直接被拿走
如果一个东西有人(A)选了 然后B也想要这个东西 那么B就会跟A商讨,
如果A有其他喜欢的东西可以选,那么就会把这个耍过的东西给B,如果A找不到替代品;
那么就会把B打一顿,不给B;
如果B有多种喜欢的东西 那么在A这碰壁了以后可以去试试别的 流程跟上面一样
如果B只喜欢这么一个东西 或者 B到处碰壁也没拿到自己喜欢的东西 那么只能饮恨而终…
而 人 喜欢 东西 => 两个点之间存在边 => 使用有向边即可 毕竟是人选物品…不需要物品选人
优化
来自大佬的题解
例题&Code
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210;
struct Edge{
int v,next;
}e[N*N];
int head[N];
int cnt;
bool vis[N];
int who[N];
inline void add(int u,int v){
e[++cnt].v=v;
e[cnt].next = head[u];
head[u]=cnt;
}
bool dfs(int u){
for(int i=head[u];i;i=e[i].next){
int v = e[i].v;
//为了dfs(who[v])设置的
//因为标为1说明这个点已经考虑过了,不可能取这个的...
//原配只能继续往后找
if(vis[v]) continue;
vis[v]=1;
if(!who[v]||dfs(who[v])){
who[v]=u;
return 1;
}
}
return 0;
}
int main(){
int n,m;
cin >> n >> m;
for(int i=1,s;i<=n;i++){
cin >> s;
for(int j=1,v;j<=s;j++){
cin >> v;
add(i,v);
}
}
int ans = 0;
for(int i=1;i<=n;i++){
ans += dfs(i);
//vis的记录是关于一个点 那么对于下个点来说肯定要清空
memset(vis,0,sizeof(vis));
}
cout << ans << '\n';
return 0;
}