“二分图匹配策略:匈牙利算法详解与应用实践“

news2024/11/25 22:32:09

二分图的最大匹配

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

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

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

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

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

输入格式

第一行包含三个整数 𝑛1、 𝑛2 和 𝑚。

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

输出格式

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

数据范围

1≤𝑛1,𝑛2≤500,
1≤𝑢≤𝑛1,
1≤𝑣≤𝑛2,
1≤𝑚≤105

输入样例:
2 2 4
1 1
1 2
2 1
2 2
输出样例:
2

匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。

uwE7FNHfzxn5RZY

等等,看得头大?那么请看下面的版本:

通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在让我们无视掉所有的单相思,你拥有的大概就是下面这样一张关系图,每一条连线都表示互有好感。

匈牙利算法的工作模式会教你这样做:

一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,连上一条蓝线

二:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,连上一条蓝线

三:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?
我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。

(黄色表示这条边被临时拆掉)

与1号男生相连的第二个女生是2号女生,但是2号女生也有主了,怎么办呢?我们再试着给2号女生的原配。重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程)

此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去

所以第三步最后的结果就是:

四: 接下来是4号男生
很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子。

就是匈牙利算法的流程,其中找妹子是个递归的过程,最关键的就是:有机会上,没机会创造机会也要上。

代码

#include<iostream>
#include <cstring>
#include<algorithm>
using namespace std;
// 邻接表存储图
int n1, n2, m;
int h[500], e[100010],ne[100010], idx = 0;
//st 标记是否递归找过, match[x]:和 x 编号的男生的编号
int st[510], match[510];
//存图函数
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 b = e[i];
        if(!st[b]){//打标记
            st[b] = 1;
            // 当前尝试点没有被匹配或者和当前尝试点匹配的那个点可以换另一个匹配
            if(match[b] == 0 || find(match[b])){
                // 和当前尝试点匹配在一起
                match[b] = x;
                return true;
            }
        }
    }
    return false;
}

int main(){
    memset(h, -1, sizeof h);
    cin >> n1 >> n2 >> m;
    // 保存图,因为只从一遍找另一边,所以该无向图只需要存储一个方向
    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++){
        memset(st, 0, sizeof st);
        //找到匹配
        if(find(i)) res++;
    }
    cout << res;
    return 0;
}

时间复杂度:对于左侧每个点,最多去尝试右侧点的个数次,所以是:o(n * m)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1827470.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ollama 多模态llava图像识别理解模型使用

参考: https://llava-vl.github.io/ https://ollama.com/blog/vision-models https://blog.csdn.net/weixin_42357472/article/details/137666022 下载: ollama run llava:13bcli使用 图片地址前面空格就行 describe this image: /ai/a1.jpg

最新版点微同城源码34.7+全套插件+小程序前后端(含安装教程)

模板挺好看的 带全套插件 自己耐心点配置一下插件 可以H5可以小程序 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89394996 更多资源下载&#xff1a;关注我。

维度建模中的事实表设计原则

维度建模是一种数据仓库设计方法&#xff0c;其核心是围绕业务过程建立事实表和维度表。事实表主要存储与业务过程相关的度量数据&#xff0c;而维度表则描述这些度量数据的属性。 以下是设计事实表时需要遵循的几个重要原则&#xff0c;来源于《维度建模》那本书上&#xff0…

正解 x86 Linux 内存管理

1&#xff0c;机器解析的思路 发现网络上大量的教程&#xff0c;多是以讹传讹地讲解 Linux 内存管理&#xff1b; 都是在讲&#xff1a; 逻辑地址 -> 线性地址 -> 物理地址 这个转换关系是怎么发生的。 上面这个过程确实是程序运行时地址的翻译顺序&#xff1b; …

Java课程设计:基于Javaweb的校园订餐系统

文章目录 一、项目介绍二、项目技术栈三、核心代码四、项目展示五、源码获取 一、项目介绍 在当今互联网高速发展的时代,大学校园内的学生生活正在发生着翻天覆地的变化。其中,校园内的餐饮服务无疑是亟需改革和创新的领域之一。 传统的校园食堂模式,往往存在就餐高峰时段拥挤…

[Cloud Networking] SPDY 协议

文章目录 1. 背景2. SPDY 之前3. SPDY 项目目标4. SPDY 功能特点4.1 SPDY基本功能4.2 SPDY高级功能 1. 背景 TCP是通用的、可靠的传输协议&#xff0c;提供保证交付、重复抑制、按顺序交付、流量控制、拥塞避免和其他传输特性。 HTTP是提供基本请求/响应语义的应用层协议。 不…

ubuntu 22.04下载和安装

ubuntu镜像: https://www.releases.ubuntu.com/22.04/ 然后下载vmwareworkstation16 密钥 ZF3R0-FHED2-M80TY-8QYGC-NPKYF

fiddler打开后,requests无法使用

Fiddler实用小技巧 错误情况 打开fiddler后&#xff0c;requests无法请求 requests.exceptions.ProxyError: HTTPSConnectionPool(hosth5api.m.taobao.com, port443): 说明 其实这是一个很小的坑&#xff0c;确也是一个很常见的坑。 在打开fiddler后&#xff0c;根据fiddle…

Linux笔记--ubuntu文件目录+命令行介绍

文件目录 命令行介绍 当我们在ubuntu中命令行处理位置输入ls后会显示出其所有目录&#xff0c;那么处理这些命令的程序就是shell&#xff0c;它负责接收用户的输入&#xff0c;并根据输入找到其他程序并运行 命令行格式 linux的命令一般由三部分组成&#xff1a;command命令、…

Cheat Engine CE v7.5 安装教程(专注于游戏的修改器)

前言 Cheat Engine是一款专注于游戏的修改器。它可以用来扫描游戏中的内存&#xff0c;并允许修改它们。它还附带了调试器、反汇编器、汇编器、变速器、作弊器生成、Direct3D操作工具、系统检查工具等。 一、下载地址 下载链接&#xff1a;http://dygod/source 点击搜索&…

微信小程序毕业设计-实验室管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

为什么用SDE(随机微分方程)来描述扩散过程【论文精读】

为什么用SDE(随机微分方程)来描述扩散过程【论文精读】 B站视频&#xff1a;为什么用SDE(随机微分方程)来描述扩散过程 论文&#xff1a;Score-Based Generative Modeling through Stochastic Differential Equations 地址&#xff1a;https://doi.org/10.48550/arXiv.2011.13…

读AI新生:破解人机共存密码笔记02进化

1. 人工智能的标准模型 1.1. 机器优化人类提供的固定目标 1.1.1. 是一条死胡同 1.1.1.1. 当你走进死胡同时&#xff0c;你最好掉头返回&#xff0c;找出走错的地方 1.2. 问题不在于我们可能无法做好构建人工智能系统的工作&…

LeetCode --- 401周赛

题目列表 3178. 找出 K 秒后拿着球的孩子 3179. K 秒后第 N 个元素的值 3180. 执行操作可获得的最大总奖励 I 3181. 执行操作可获得的最大总奖励 II 一、找出K秒后拿着球的孩子 这题可以直接模拟&#xff0c;从前往后&#xff0c;再从后往前走k次&#xff0c;最后直接返回…

小红书教程简化版,从0开始走向专业,小红书-主理人培养计划 (13节)

课程目录 1-小红书分析与拆解.mp4 2-小红书电商玩法.mp4 3-小红书基础信息设置10_1.mp4 4-小红书如何开店&#xff1f;.mp4 5-小红书店铺设置&#xff08;1&#xff09;.mp4 5-小红书店铺设置.mp4 6-小红书笔记制作与产品发布.mp4 7-小红书运营的文案与标题.mp4 8-小红…

网络编程(二)TCP

一、TCP网络编程 网络编程模型&#xff1a; C/S模型&#xff1a;客户端服务器模型 优点&#xff1a; 客户端可以缓存一些数据&#xff0c;使用时直接在本地读取&#xff0c;无需每次重新下载&#xff1b; 由于客户端和服务器都是自己开发的&#xff0c;可以自定义协议 缺点&a…

数据结构C语言版:顺序表基本操作的实现

参考教材&#xff1a;数据结构C语言版&#xff08;严蔚敏&#xff0c;吴伟民编著&#xff09; 目录 线性表的基本操作&#xff1a; 1&#xff1a;线性表L的初始化(参数用引用) 2&#xff1a;销毁线性表L 3&#xff1a;清空线性表L 4&#xff1a;求线性表L的长度 5&#xf…

⌈ 传知代码 ⌋【算法】实体关系抽取

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【内存管理之堆内存】

1.栈上的基元 2.栈上的聚合对象 3.手动分配和释放 4.分配堆内存 5.数组内存分配和释放 6.数组内存分配 7.不要使用野指针 8.黑暗时代

Windows如何找回永久删除的文件?完整教程看完即会!

可以找回永久删除的文件&#xff1f; 你是否也在Windows 10中永久删除过文件&#xff1f;什么是永久删除&#xff1f;通常有5种方法可以永久删除文件&#xff1a; 正常删除文件&#xff0c;然后在回收站中再次删除。使用命令提示符&#xff1a;“del”删除文件。使用“ShiftD…