恋爱大法--匈牙利算法--二分图的最大匹配问题

目录

应用场景:

问题描述

算法的注意点:

实现代码:

总结:


应用场景:

匈牙利算法,用于查找二分图中能够实现最大匹配的最大数目,也称“恋爱大法”。

算法特点:待字闺中,据为己有;名花有主,求他放手。

匈牙利算法其实质可以用男女生交往来形象说明,假设左边点为男生,右边点为女生,这个算法的核心就是寻找左边男生能够找到对象的个数。在找对象,也就是匹配的过程中,需要对左边点进行循环遍历他看上的所有女生;此时分两种情况:1.如果当前男生小a看上的女生没有对象 则皆大欢喜 该男生女生匹配成功,2.如果当前女生有对象,那么去循环遍历女生的对象小b,如果小b还有其他喜欢的女生,也就是小b的备胎,那么让小b和备胎进行匹配,小a则顺利的和女生交往,这就是匈牙利算法的恋爱准则,非常现实hh。


问题描述

给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

二分图的匹配:给定一个二分图 G,在 G 的一个子图 M 中,M 的边集{E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

输入格式

第一行包含三个整数 n1、 n2 和 m。

接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v 之间存在一条边。

输出格式

输出一个整数,表示二分图的最大匹配数。

数据范围

1≤n1,n2≤500,
1≤u≤n1,
1≤v≤n2,
1≤m≤105

输入样例:

2 2 4
1 1
1 2
2 1
2 2

输出样例:

2

 


算法的注意点:

匈牙利算法的核心我个人觉得是match数组和st数组的相互作用。

在匈牙利算法中需要注意的两点,也就是关于st数组的两个注意点:

1.每次遍历男生进行匹配的时候,要把st数组全部清空,其意义也就是每个男生可以去尝试进行交往的女生是所有他喜欢的女生,而不是没有对象的女生。(hhh狗头)

2.在find函数中 判断!st[j]并设置st[j]=true的作用是避免出现死循环。更新st: st数组的作用是又有一个左边的点再次匹配到某个右边已经有边的点时,右边的点对应的那条线的左边的点,去寻在新的“对象“时,不再去找原来的右边的那个点。当左一和右一已经匹配成功时,左二也看上了右一,此时就需要让左一遍历其他的“备胎”,如果没有st数组的话,左一再去遍历所有喜欢的女生,又会从右一开始,这就使得find(1)无限循环,如果设置了st数组并更新,在左一再去遍历喜欢的女生时,就不会再遍历右一了,因为已经将st数组设置成了true,不会再进入判断。


实现代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510, M = 100010;
int idx,e[M],ne[M],h[N];
int match[N];//用于存储女生匹配到的男生
bool st[N];//用于记录是否已经被匹配
int n1,n2,m;

void add(int a,int b){
    e[idx] =b,ne[idx] = h[a],h[a] = 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(){
    cin>>n1>>n2>>m;
    memset(h,-1,sizeof(h));
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    int res = 0;//用于记录最大能匹配的数量
    for(int i =1;i<=n1;i++){
        //对于每个男生来说 开始时所有女生都能遍历到 所以将st数组设置为false
        memset(st,false,sizeof(st));
        //如果find能找到 res加1
        if(find(i)) res++;
    }
    cout<<res<<endl;
    return 0;
}

总结:

恋爱大法虽好,只当玩笑,恋爱还是认真谈的好哈哈哈。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值