二分图匹配(匈牙利算法)

概念

在这里插入图片描述

匈牙利算法

这个算法的过程是这样的;

枚举每一个左部点 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

AcWing 1394. 完美牛棚

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值