匈牙利算法入门

匈牙利算法详解 匈牙利算法(Hungarian Algorithm)是一种组合优化算法(combinatorial optimization algorithm),用于求解指派问题(assignment problem),算法时间复杂度为O(N^3)。Harold Kuhn发表于1955年,由于该算法基于两位匈牙利数学家的早期研究成果,所以被称作“匈牙利算法”。假设有三位工人A,B和C,需要分配他们每人完成一件工作;对于不同的工作他们所需要花费的时间不同,如下表所示。问题就是要找到一套耗时最小的指派方案。 阅读详情

最近了解了一下二分图匹配,发现这篇博客写的挺好,自己总结的话也总结不了那么好,于是就转载过来了,出处http://www.cnblogs.com/budapeng/articles/3273293.aspx


首先来了解下一些概念性的东西。

二分图:  

  二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。图一就是一个二分图。

匈牙利算法:

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

Hall定理:

  二部图G中的两部分顶点组成的集合分别为X, Y; X={X1, X2, X3,X4, .........,Xm}, Y={y1, y2, y3, y4 , .........,yn}, G中有一组无公共点的边,一端恰好为组成X的点的充分必要条件是:X中的任意k个点至少与Y中的k个点相邻。(1≤k≤m)

匹配:

  给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配。图一中红线为就是一组匹配。

未盖点:

  设Vi是图G的一个顶点,如果Vi 不与任意一条属于匹配M的边相关联,就称Vi 是一个未盖点。如图一中的a3、b1。

交错路:

  设P是图G的一条路,如果P的任意两条相邻的边一定是一条属于M而另一条不属于M,就称P是一条交错路。如图一中a2->b2->a1->b4。

可增广路:

  两个端点都是未盖点的交错路叫做可增广路。如图一中的b1->a2->b2->a1->b4->a3。

顶点的数目:

  图中顶点的总数。

最大独立数:

  从V个顶点中选出k个顶,使得这k个顶互不相邻。 那么最大的k就是这个图的最大独立数。

最小顶点覆盖数:

  用最少的顶点数k来覆盖图的所有的边,k就是这个图的最小顶点覆盖数。

最大匹配数:

  所有匹配中包含的边数最多的数目称为最大匹配数。

顶点的数目=最大独立数+最小顶点覆盖数(对于所有无向图都有效)

最大匹配数=最小顶点覆盖数(只对二分图有效)

 

  这么多概念罗列出来了,下面放个实际中可能遇到的问题。其实就是算法竞赛中的一道题目,简化阐述下。

问题:

  幼儿园有G个女孩、B个男孩。女孩之间都相互认识,男孩之间都相互认识,部分男女之间相互认识。要求从中选出一部分小孩,他们之间都要相互认识,求能从中选出的最多人数。

分析:

  可以按男女画出二分图。因为要求选出的小孩都要相互认识,则可以在相互不认识的小孩之间连线,这样只要小孩之间没有线直接相连,那么他们就肯定就是相互认识的了。也就因此转化为了求这个二分图的最大独立数。

  为了便于理解,首先我们来做个游戏。假设现在有5个男孩(b1,b2,b3,b4,b5)、五个女孩(g1,g2,g3,g4,g5)。b1不认识g1,g2;b2不认识g2,g3;b3不认识g2,g5;b4不认识g3;b5不认识g3,g4,g5。男孩女孩站两排,相互不认识的他们之间用一根线相连。得到的图如下:

  因为相互不认识的小孩之间会有一根线,所以如果我们想得到相互都认识的小孩,那么最终留下的小孩他们的手里都不能握有线了,很简单如果他们手中还有线,那就说明留下的人还有他不认识的。这样,之前的问题也就转变为了如何去除最少的小孩,使留下的小孩手中没有线。再换一种说法,也就是怎么在这么多小孩中找出最少的人,他们握有所有的线。这下就转换为了寻找最小顶点覆盖数。

  这样如果找到了最小顶点覆盖数,我们又知道顶点数(所有的小孩的数目),就可以求出最大独立数(现场留下的小孩)。

  又因为对于二分图,最大匹配数=最小顶点覆盖数。这个问题进而也就变成了求解最大匹配数。而匈牙利算法正是用来求最大匹配数的一个很好的方法。

  

  下面我们就来看看匈牙利算法的具体流程。

  上面的流程有些抽象,具体要怎么来找增广路呢,下面给出具体操作的流程图。

  是不是感觉有些乱,让我们来一步一步的分析。为了简化步骤我们用下图来分析

第一个最外层的循环从x1开始:

  按照流程图,第一次肯定有xi了,清空标记后,yi肯定也是没有标记的了。然后对yi进行标记,第一次M自然也是空的了,M中加入(x1,y1)得到新的M{(x1,y1)},于是得到下图。

最外层循环到了x2:

  好,接下来最大匹配数加1,循环继续。下面就该轮到x2了。首先清空Y的标记。

  这时x2再找到y1时它已经没有标记了,这时再来标记它。但y1已经在M中了,它的对应顶点为x1。所以接下来x1要更新关联点。

  由x1开始查找时,在Y中y1已经被标记了,只能找下一个顶点,于是便找到了y2。y2未被标记,标记它。x1的关联点更新为y2,x2的关联点更新为y1。因此得新的M为{(x2,y1),(x1,y2)}

   好,最大匹配数加1,循环继续。清空Y中标记。

最外层循环到了x3:

  下面就轮到x3了。x3找到y1,y1未标记,标记之。

  y1的关联是x2。又轮到x2找了。x2找到y1,但y1已被标记,于是便找到y2。y2未被标记,标记之。

  y2的关联为x1,x1开始找。x1找到y1,y1已被标记,找到y2,y2已被标记。找到y3,y3未被标记,标记之。同时y3没有关联。更改x1的关联为y3。

  原(x1,y2)的关联也因为x1的改变,变为了(x2,y2)

  同时新增关联(x3,y1)更新M为{(x3,y1),(x2,y2),(x1,y3)}。最大匹配数加1。这时已经没有更多的X中顶点可选了。最大匹配数就这样被找出来了。

  细心的人可能已经看出来了,有M'{(x2,y1),(x1,y2)},最后找出的路径x3->y1->x2->y2->x1->y3是一条增广路径。

  下面说一些增广路的特性,匈牙利法的正确性验证自己有兴趣可以证明下。

  (1)有奇数条边。
  (2)起点在二分图的左半边,终点在右半边。
  (3)路径上的点一定是一个在左半边,一个在右半边,交替出现。
  (4)整条路径上没有重复的点。
  (5)路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
  (6)把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个。

  接下来就要用计算机来实现这个算法的过程了。相信有了上面的基础,已经不难完成了。

  我是用c++编译的,程序很多地方肯定还有待优化,主要是为了展示算法流程。到这里至少应该对匈牙利算法有所了解了,算法讲解到此结束。

复制代码
#include <stdio.h>
#include <string.h>

#define MAXNUM 1000
//递归
//xi 二分图左部中的顶点
//ytotal 二分图右部顶点总数
//relation xy之间的关联关系
//link xy之间的匹配
//y的标记
bool recursion(const int xi, const int ytotal, const bool relation[][MAXNUM], int link[], bool* sign)
{
    for(int i = 0; i < ytotal; i++)
    {
        if(relation[xi][i] && !sign[i])//有关联并且没被标记
        {
            sign[i] = true;//标记
            if(link[i] == -1 || recursion(link[i], ytotal, relation, link, sign))//y没有有匹配则更新y的匹配;y有匹配则用它的匹配继续查找
            {
                link[i] = xi;//更新y的匹配 
                return true;
            }    
        }
    }
    return false;
}

//匈牙利算法
//xtotal 二分图的左部包含顶点总数
//ytotal 二分图的右部包含顶点总数
//xy之间的关联
int Hungary(const int xtotal, const int ytotal,const bool relation[][MAXNUM])
{
    int link[MAXNUM][2];//与y匹配的x
    memset(link, -1, sizeof(link));
    int cnt = 0;//最大匹配数
    for(int i = 0; i < xtotal; i++)
    {
        bool sign[MAXNUM] = {false};//清空标记
        if(recursion(i, ytotal, relation, link[i], sign))//寻找增广路径
        {
            cnt++;
        }
    }
    return cnt;
}

int main(int argc, char** argv)
{
    while(true)
    {
        int boytotal = 0;
        int girltotal = 0;
        bool relation[MAXNUM][MAXNUM] = {false};
        //获取男孩总数
        do 
        {
            fflush(stdin);
            printf("请输入男孩总数(不大于%d):\n", MAXNUM);
            scanf("%d",&boytotal);
        }while(0 == boytotal || boytotal > MAXNUM);
        printf("男孩总数输入成功。\n");
        printf("------------------------\n");

        //获取女孩总数
        do 
        {
            fflush(stdin);
            printf("请输入女孩总数(不大于%d):\n", MAXNUM);
            scanf("%d",&girltotal);
        }while(0 == girltotal || girltotal > MAXNUM);
        printf("女孩总数输入成功。\n");
        printf("------------------------\n");

        //获取相互不认识的男女
        do
        {
            int boyno = 0;
            int girlno = 0;
            fflush(stdin);
            printf("请输入相互不认识的异性小孩,如第一个男孩不认识第二个女孩则输入1,2:\n");
            scanf("%d,%d",&boyno, &girlno);
            if(boyno>0&&boyno<=boytotal&&girlno>0&&girlno<=girltotal)
            {
                relation[boyno-1][girlno-1] = true;
                char ret = '\0';
                fflush(stdin);
                printf("一对互不认识的男女输入成功,是否结束输入?(Y/N)\n");
                scanf("%c",&ret);
                if('Y' == ret || 'y' == ret)
                {
                    break;
                }
            }
        }while(true);
        printf("------------------------\n");

        
        printf("男孩个数:%d;女孩个数:%d;小孩总数:%d\n",boytotal,girltotal,boytotal+girltotal);
        //寻找最大匹配
        int tmp = Hungary(boytotal, girltotal, relation);
        printf("最大匹配数:%d\n", tmp);
        printf("最多可以留下人数:%d\n", boytotal+girltotal-tmp);
        printf("------------------------\n");

        char ret;
        fflush(stdin);
        printf("是否退出?(Y/N)\n");
        scanf("%c",&ret);
        if('Y' == ret || 'y' == ret)
        {
            break;
        }
        printf("------------------------\n");
    }
    
    return 1;
}
【图论】图文详解匈牙利算法 匈牙利算法一、一些概念1.二分图2.二分图的匹配二、匈牙利算法的实现步骤1.情况一(你是我的唯一)2.情况二(你们都是我的翅膀)3.情况三(我会把你抢过来)4.情况四(我爱的人已经有了爱人)三、匈牙利算法的代码实现 一、一些概念 1.二分图 一定不含有奇数环,可能包含长度为偶数的环, 不一定是连通图 二分图是图论中的一种特殊模型。设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in 阅读详情

相关推荐

Autodesk激活无无网络选项?许可类型与脱机激活排查修复指南

软件许可激活是保障正版授权正常使用的核心环节,常见的授权模式包括单机版许可和网络版许可,两者在认证机制和应用场景上有所区别。单机版离线授权依托 FlexNet Licensing Service 等底层服务组件,在断网或内网环境下为用户提供可靠的技术支持与授权验证路径。然而在实际部署中,激活窗口并不总是显示“无网络激活方式”入口,这可能与许可类型选择、网络环境干扰、组件安装残留或系统时间偏差有关。理解入口的动态呈现逻辑与排查顺序,有助于在 AutoCAD、Revit 等 Autodesk 产品中高效解决脱机

weixin_28709649的博客 355

(二)匈牙利算法简介

视觉追踪基础,匈牙利算法简介

机器人视觉感知 3万+

AIDD-人工智能药物设计-构建基于机器学习方法的在线预测平台高准确预测药物诱导骨毒性

在此基础上,提取多种药物分子特征,包括分子指纹(如MACCS、Morgan、RDKit、TopologicalTorsion、AtomPairs与Descriptors)及分子图谱,通过Transformer编码器与神经网络进行机器学习模型训练。最后,将训练好的模型部署为在线Web服务器(BoneToxPD),供用户快速预测药物的骨毒性。本研究不仅在骨毒性预测的准确性方面取得了突破,还在模型解释性方面提供了新的视角,通过注意力机制精准识别出影响骨毒性的关键化学基团,推动药物研发领域更安全、更高效的发展。

itwangyang520的博客 1079

【程序人生】Hungarian Algorithm——匈牙利算法

1.匈牙利算法(一种组合优化算法)的原理以及时间复杂度

Zhang_Chen_的博客 1770

[数字电路]用与非门实现BCD译码器驱动数码管

Hello,大家好。这里是xdd_core,好久不见。今天来和大家聊聊大一数字电路课程的一个课设。# Key word:BCD Decoder,Proteus8.x,NAND Gate,Digital Circuit# 流程:Proteus8.x仿真电路并绘制PCB导出Gerber文件打样,最终实物验证。# 以下为我对这个课设的report(里面对整个设计做了详细介绍,并设计了完整的验证电路) 感谢观看,仅供参考,未经作者允许,禁止转载/抄袭,本文已上传至数据库,查重必挂QAQ BCD to 7-Segme

xddcore的博客 6012

AHB不对称半桥反激电路设计(三)主要器件参数规格计算

本文介绍了AHB拓扑变压器的设计步骤与核心参数计算,包括主控芯片选择、工作原理分析及参数计算。作者选择DK87XXD集成MOS方案,详细阐述了输入电压范围、反射电压限定、匝比计算、工作频率设定、原副边电流值、电感量计算、磁芯选择、匝数计算、谐振电容设计等关键步骤。通过公式推导与实例计算,展示了150W电源的变压器设计过程,最终确定匝比5.5、原边22匝、副边4匝、电感量200uH等参数。文章还讨论了谐振电容与漏感的关系,为后续调试提供理论基础。该设计方法结合理论分析与工程实践,适用于AHB拓扑电源开发。

【Simon】的博客 3332

【图论】匈牙利算法入门

这段时间要沉迷刷题一段时间了,就让优快云陪我一起吧! 原文链接戳这里:趣写算法系列之–匈牙利算法 这个教程真的是讲的很好,很适合新手上来去理解匈牙利算法。但希望大家每次看算法不只是看完这么简单,还要动手实战,在这里我给大家提供两道经典例题。 POJ 3020、hdu 2063 下面就进入正题吧! ================================================...

Johnson的博客 637

跨厂商网络设备的RADIUS认证:Windows NPS的兼容性与最佳实践

本文详细探讨了Windows NPS在多厂商网络环境中的RADIUS认证实践,特别针对华为、华三、思科等主流设备的兼容性问题提供解决方案。从基础配置到高级优化,涵盖VSA属性映射、认证协议选择及安全加固措施,帮助企业实现统一身份认证并提升网络安全性。

weixin_29213827的博客 421

二分图匹配 【匈牙利算法】 从入门到熟练

二分图匹配 匈牙利算法 先让我来介绍一下二分图是什么吧! 这就是一种最常见的二分图。也就是左右两边相连,左边与左边不连,右边也不连的一幅图。把左边看成集合A,右边看成集合B,每条边都连接A与B中的点。 讲完二分图,我们在了解一下匹配是什么。 在二分图中,任意两条边都没有公共顶点。 让我们看一幅图: 红色线条就是匹配的线条,当然,不...

aiweiluan5095的博客 152

LeRobot 入门教程(十七)NVIDIA IsaacLab Arena 集成

LeRobotEnvHub现已集成IsaacLabArena实现GPU加速仿真,支持GR1/G1/伽利略人形机器人实体和多种操作任务。安装需满足CUDA GPU、Ubuntu系统和IsaacSim 5.1.0要求,通过conda环境配置依赖项。系统提供SmolVLA和PI0.5等预训练策略评估功能,支持视频录制和并行环境配置。环境配置选项涵盖机器人实体、任务类型、观测维度等参数,并包含针对CUDA内存、视频录制等常见问题的解决方案。此外,LightWheel AI还通过LW-BenchHub引入了包含268

2506_90492529的博客 1246

R语言绘制森林图

运行上述代码后,将会生成一个标题为"森林图示例"的森林图。通过以上代码示例,你可以根据自己的数据集和需求创建定制的森林图。在实际应用中,你还可以进一步调整图形的样式,添加图例、坐标轴标签等,以使森林图更加美观和易于理解。在数据可视化领域,森林图是一种常用的图形类型,用于展示多个分类变量之间的关系。本文将介绍如何使用R语言创建森林图,并提供相应的源代码示例。森林图通常由垂直的线段表示不同类别的观测值,并且线段的长度表示数值变量的大小。上述代码中,我们为不同的类别分别指定了蓝色和红色作为颜色映射关系。

TechNovaX的博客 1045

一文搞懂匈牙利算法【入门版】

acm新手快速入门匈牙利算法

zlq7777的博客 876

全球首发48V架构的Cybertruck,到底牛在哪?| 深扒特斯拉高压系统架构

特斯拉Cybertruck作为全球首款标配48V架构的量产车,在电气系统架构上进行了多项创新。首先,它采用以太网连接高压控制器与后域控制器,提升了数据传输效率和智能化水平。其次,Cybertruck引入了Pyro烟火断开装置,用于碰撞时快速断开电池连接,提高安全性。在电流监测方面,特斯拉既保留了传统的Shunt分流器技术,又引入了更先进的磁通门电流传感器,后者具有无温漂、完全隔离等优势。48V供电系统在降低电流损耗方面表现优异,但也面临电弧风险、盐水腐蚀等挑战。Cybertruck的48V系统通过PCS供电

weixin_43199439的博客 1347

带你入门多目标跟踪(三)匈牙利算法&KM算法

匈牙利算法(Hungarian Algorithm)与KM算法(Kuhn-Munkres Algorithm)是做多目标跟踪的小伙伴很容易在论文中见到的两种算法。他们都是用来解决多目标跟踪中的数据关联问题。 对理论没有兴趣的小伙伴可以先跳过本文,进行下一篇的学习,把匈牙利算法这些先当作一个黑箱来用,等需要了再回过头来学习理论。但个人建议,至少要明白这些算法的目的与大致流程。 如果大家用这两种算...

Nieson2012的专栏 1万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

POJ - 1469 COURSES (匈牙利算法入门题)

题意:   P门课程,N个学生。给出每门课程的选课学生,求是否可以给每门课程选出一个课代表。课代表必须是选了该课的学生且每个学生只能当一门课程的。 题解:   匈牙利算法的入门题。 #include <iostream> #include <cstring> #include <cstdio> #include <vecto...

weixin_30536513的博客 70

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

二分图匹配入门之 匈牙利算法

什么是二分图,什么是二分图的最大匹配,这些定义我就不讲了,网上随便都找得到。二分图的最大匹配有两种求法,第 一种是最大流(我在此假设读者已有网络流的知识);第二种就是我现在要讲的匈牙利算法。这个算法说白了就是最大流的算法,但是它跟据二分图匹配这个问题的 特点,把最大流算法做了简化,提高了效率。匈牙利算法其实很简单,但是网上搜不到什么说得清楚的文章。所以我决定要写一下。 最大流算法的核心...

weixin_30640291的博客 86

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

图论入门---匈牙利算法的理解

【书本上的算法往往讲得非常复杂,我和我的朋友计划用一些简单通俗的例子来描述算法的流程】 匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。 -------等等,看得头大?那么请看下面的版本: 通过数代人的努力,你终

thoughtspark的博客 1382

hdu 2063 过山车 (匈牙利算法入门)

题目链接 感觉我写了很多算法入门题,但写起题目来就像没入门一样。这是一个非常神奇的体验。 题意:给你两个集合,求最大的匹配数。 思路:枚举男生,used代表这一轮匹配中女生是否访问,nxt【i】代表跟第i位女生匹配的男生,line保存的是两个集合中元素的联系。 #include<bits/stdc++.h> using namespace std; const int...

我是蒋卫升呀~ 386

简述匈牙利算法求解最大匹配的主要过程。_带你入门多目标跟踪(三)匈牙利算法&KM算法...

匈牙利算法(Hungarian Algorithm)与KM算法(Kuhn-Munkres Algorithm)是做多目标跟踪的小伙伴很容易在论文中见到的两种算法。他们都是用来解决多目标跟踪中的数据关联问题。对理论没有兴趣的小伙伴可以先跳过本文,进行下一篇的学习,把匈牙利算法这些先当作一个黑箱来用,等需要了再回过头来学习理论。但个人建议,至少要明白这些算法的目的与大致流程。如果大家用这两种算法的名字...

weixin_32926649的博客 2082

Asteroids(匈牙利算法入门)

Asteroids Time Limit:1000MS Memory Limit:65536K Total Submissions:16211 Accepted:8819 Description Bessie wants to navigate her spaceship through a dangerous asteroi...

weixin_30265171的博客 99
上一篇: 动态规划-hdu1203
下一篇: Linux系统编程-文件IO(一)
UKey_
博客等级 码龄10年 258粉丝 186原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值