匈牙利算法

匈牙利算法:是一种在多项式时间内求解任务分配问题的组合优化算法,并推动了后来的原始对偶方法

时间复杂度:O(nm)

适用场景:二分图的最大匹配

核心思想:增广路径,即当左边集合的点1匹配右边的点2为已匹配时,会找到上一个左边指向该右边已匹配点2的节点3,并尝试将该节点3转向另一个节点4,若果节点4也匹配则重复该操作,如果未匹配则称这条新路径为增广路径

二分图:又称作二部图,是图论中的一种特殊模型。图中的所有顶点可以分为两个集合,集合内部没有边存在,边只存在于集合之间,即所有边的顶点分别属于不同集合

二分图特性:二分图一定不含有奇数环

二分图只有偶数环,因为只有偶数环才可以保证成环的条件下还能保证在同一个集合内的环节点没有边存在,而奇数环的出现说明在这个环中至少有两个节点是在同一集合内,并且它们之间还存在边

最大匹配:每条边的两端都是不同集合的节点,在节点不重复的情况下,边数最多

参考代码:

例题:二分图的最大匹配​​​​​​​

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//题目给定的点数、边数限制
const int N = 510, M = 100010;
//输入的左边集合点数n1,右边集合点数n2以及边数m
int n1,n2,m;
//存储边数的邻接表
int h[N],e[M],ne[M],idx;
//下标表示右边集合节点x,其值表示左边集合节点y
int match[N];
//存储右边集合是否已匹配
bool st[N];

void add(int a,int b){
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx;
    idx ++ ;
}

bool find(int x){
    //对传入的节点进行遍历所有可匹配的右边点
    for(int i = h[x] ; i != -1 ; i = ne[i]){
        int j = e[i];
        //如果右边节点未匹配
        if(!st[j]){
            //则将右边节点设为已匹配
            st[j] = true;
            //如果右边节点为未匹配或者为右边节点的现任节点找到新的匹配点
            if(match[j] == 0 || find(match[j])){
                //将右边节点的匹配对象换成自己
                match[j] = x;
                //返回配对成功
                return true;
            }
        }
    }
    //返回配对失败
    return false;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin >> n1 >> n2 >> m;
    int a,b;
    memset(h,-1,sizeof h);
    while (m--){
        cin >> a >> b;
        //仅需存储从左到右的边即可,只对左边集合节点进行操作
        add(a,b);
    }
    
    //存储匹配数
    int res;
    
    //对左边集合的节点进行遍历
    for(int i = 1 ; i <= n1 ; i++){
        memset(st,false,sizeof st);
        if(find(i)){
            res++;
        }
    }
    cout << res << endl;
    return 0;
}
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏大橙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值