搜索与图论:匈牙利算法

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

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

二分图的最大匹配:

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);
}
相关推荐
W23035765735 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
minji...6 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
语戚7 小时前
力扣 968. 监控二叉树 —— 贪心 & 树形 DP 双解法递归 + 非递归全解(Java 实现)
java·算法·leetcode·贪心算法·动态规划·力扣·
skywalker_117 小时前
力扣hot100-7(接雨水),8(无重复字符的最长子串)
算法·leetcode·职场和发展
bIo7lyA8v8 小时前
算法稳定性分析中的输入扰动建模的技术9
算法
CoderCodingNo8 小时前
【GESP】C++三级真题 luogu-B4499, [GESP202603 三级] 二进制回文串
数据结构·c++·算法
sinat_286945198 小时前
AI Coding 时代的 TDD:从理念到工程落地
人工智能·深度学习·算法·tdd
炽烈小老头8 小时前
【 每天学习一点算法 2026/04/12】x 的平方根
学习·算法
ASKED_20199 小时前
从排序到生成:腾讯广告算法大赛 2025 baseline解读
人工智能·算法