AcWing 861.二分图的最大匹配(匈牙利算法)

Issue:

在这里插入图片描述

Meaning:

  1. 可以理解为有 n 1 n_1 n1个男生和 n 2 n_2 n2个女生,然后有m对感情基础,然后要两两配对,求能配对成功的最大值;

Thinking:

  1. 构建 n 1 n_1 n1个链表,把男生作为表头,连接和他有感情基础的所有女生;
  2. 只要男生主动找女生就行,所有只需要add从男生到女生的有向图即可;
  3. 依次遍历 n 1 n_1 n1个男生,让他们依次找对象,如果能找到,就答案res++;
  4. 每个男生依次遍历有感情基础的女生,用st[]数组来存是否追求过,追求过失败了就不能再追求;
  5. 用match[j]数组表示女生 j j j已经匹配的男生;
  6. 如果match[j] == 0, 表示目前的女生还没有被匹配, x ∈ n 1 x \in n_1 xn1可以直接匹配;
  7. 如果match[j] != 0, 那么就看match[j]这个男生是否能换一个,如果能换,那也可以匹配;
  8. 找不到,就换链表里下一个女生;
  9. 每个女生都不能和x匹配成功,那么x就不能为答案做出贡献;
  10. 时间复杂度 O ( n m ) O(nm) O(nm),实际远小于 O ( n m ) O(nm) O(nm)

Code:

#include <cstring>
#include <iostream>

using namespace std;

const int N = 510, M = 100010;

int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];  //match[j], j表示的是n2中的点,数组存的值是n1的点,表示当前点j(n2中的)和n1中匹配的点
bool st[N];  //用来记录n2中的点是否已经追求过

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])  //依次遍历所有x可以匹配的点
    {
        int j = e[i];
        if (!st[j])  //如果当前这个点还没有被追求过
        {
            st[j] = true;  //标记j小姐已经被追求过了,能不能成功还要看后面,记住x是n1的点,j是n2的点
            if (match[j] == 0 || find(match[j]))  //如果match[j]==0表示j还没有在n1中找到相匹配的点
            {                                     //如果j已经有了匹配的对象了,看j的对象能不能再找一个新的其他的对象
                match[j] = x;                     //要是能找到,就让j的前男友和新的女朋友匹配,当前女生和x这个男生匹配
                return true;                      //找到了一个匹配对象,就可以返回true了
            }                                     //如果j的现男友不能找到另外一个新的女朋友,那么x就找他下一个心仪的女生
        }
    }

    return false;  //一直找不到,x就只能单身了
}

int main()
{
    scanf("%d%d%d", &n1, &n2, &m);

    memset(h, -1, sizeof h);

    while (m -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b);  //只需要管一边的匹配就可以了,所以可以当做有向图来插入
    }

    int res = 0;  //记录答案
    for (int i = 1; i <= n1; i ++ )  //依次匹配n1的每一个点
    {
        memset(st, false, sizeof st);  //在找对象之前,所有女生暂定为可以追求的目标
        if (find(i)) res ++ ;  //find(i)返回true,表示匹配成功
    }

    printf("%d\n", res);

    return 0;
}

Tips:

  1. 匈牙利算法模板题。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值