搜索与图论:匈牙利算法

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

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

二分图的最大匹配:

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);
}
相关推荐
Discipline10292 小时前
尼泊尔河流流量:天气驱动的预测与高流量风险
人工智能·算法
XuCoder2 小时前
改一个数,右边全得重算,这题怎么扛住两万次查询
算法
小羊没烦恼!2 小时前
在Scrum中实施敏捷建模
java·开发语言·windows·算法·c#
weixin_307779132 小时前
基于睿擎工业开发平台的预训练视觉模型轻量化适配与低代码部署优化
开发语言·算法
hold?fish:palm3 小时前
45 二叉树的右视图
开发语言·c++·算法
粤鼎恒业3 小时前
惠州工厂电子料回收厂家推荐:从交接单反推筛选标准
大数据·数据库·算法·硬件架构·硬件工程·pcb工艺·材料工程
小爷毛毛(卓寿杰)4 小时前
【Agent 意图识别】输出协议、评估与置信度
人工智能·算法·大模型·prompt·大语言模型·agent
优质酸酸乳4 小时前
力扣100题之21合并两个有序链表
算法·leetcode·链表
旖旎夜光4 小时前
LeetCode 137 : 只出现一次的数字 II(位运算) —— 题解
c++·笔记·学习·算法·leetcode·力控
旋生万物4 小时前
Agent System Prompt 注入螺旋公理:让 AI 推理不跑偏的可复制模板(附完整 Prompt)
人工智能·算法