搜索与图论:匈牙利算法

将所有点分成两个集合,使得所有边只出现在集合之间,就是二分图

二分图:一定不含有奇数个点数的环;可能包含长度为偶数的环, 不一定是连通图

二分图的最大匹配:

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 510 , M = 100010;
int n1,n2,m;
int h[N],ne[M],e[M],idx;//邻接表
bool st[N];
int match[N];

void add(int a , int b)
{//头插法
    //如图 如1与2之间要有一条线,让2的ne为1,再让h[1]为2的索引。
    //这样h[1]就是1节点存的最后一个相连的点,如图就是7节点。
    //而在索引表内部,通过头插法的方式(即每次ne指向上一个点(h存的就是上一个点)),索引表为:7->4->2
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int find(int x)
{
    //遍历自己喜欢的女孩
    for(int i = h[x] ; i != -1 ;i = ne[i])
    {
        int j = e[i];
        if(!st[j])//如果在这一轮模拟匹配中,这个女孩尚未被预定
        {
            st[j] = true;//那x就预定这个女孩了,这里预定是防止她男朋友找其他喜欢的女孩时不重复找这个
            //如果女孩j没有男朋友,或者她原来的男朋友能够预定其它喜欢的女孩。配对成功
            if(!match[j]||find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
    //自己中意的全部都被预定了。配对失败。
    return false;
}

int main()
{
    memset(h,-1,sizeof h);
    scanf("%d%d%d",&n1,&n2,&m);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }

    int res = 0;
    for(int i = 1; i <= n1 ;i ++)
    {  
        //因为每次模拟匹配的预定情况都是不一样的所以每轮模拟都要初始化
        memset(st,false,sizeof st);
        if(find(i)) res++;//找到一条边,则res++
    }  

    printf("%d\n",res);
}
相关推荐
爱睡懒觉的焦糖玛奇朵36 分钟前
【工业级落地算法之人员摔倒检测算法详解】
人工智能·python·深度学习·神经网络·算法·yolo·目标检测
小辉同志36 分钟前
78. 子集
算法·leetcode·深度优先
Book思议-1 小时前
【数据结构】二叉树入门全解:从定义、性质到经典真题
数据结构·算法·二叉树
stolentime2 小时前
通信题:洛谷P15942 [JOI Final 2026] 赌场 / Casino题解
c++·算法·洛谷·joi·通信题
初生牛犊不怕苦2 小时前
与AI一起学习《C专家编程》:数组与指针
c语言·学习·算法
Kk.08022 小时前
数据结构|排序算法(二) 冒泡排序
数据结构·算法·排序算法
沛沛rh453 小时前
深入并发编程:从 C++ 到 Rust 的学习笔记
c++·笔记·学习·算法·rust
Kk.08023 小时前
数据结构|排序算法(二) 希尔排序
数据结构·算法·排序算法
AI医影跨模态组学3 小时前
NPJ Precis Oncol(IF=8)复旦大学肿瘤医院等团队:基于生境CT放射组学解析可切除非小细胞肺癌时空异质性预测新辅助化疗免疫治疗病理反应
大数据·人工智能·算法·医学·医学影像