【匹配】匈牙利匹配算法

every blog every motto: You can do more than you think.
https://blog.csdn.net/weixin_39190382?type=blog

0. 前言

匈牙利匹配算法

1. 正文

1.1 基础概念

二分图

顶点分为两个集合,集合间顶点相连,集合内点不相连

请添加图片描述

匹配

一个匹配就是一个边的集合,其中,任意两条边不存在公共的顶点

最大匹配

上图中,我们能找到多组匹配,在这其中,所含匹配变数最多的的匹配,成为最大匹配。

交替路

从一个未匹配的点出发,依次经过非匹配边,匹配边,非匹配边,这样形成的路称为交替路

增广路

从一个未匹配的点出发,走交替路,如果途径另一个未匹配点(起点不算),则这条交替路称为增广路

1.2 算法流程

1.2.1 通俗理解

概括: 先到先得,能让则让

对于如下已有的匹配,我们需要寻找他的最大匹配。
请添加图片描述

1.2.2 步骤

下面以经典的配对情景进行说明。

现在有boys和girls两个点集,每个人有各自的暧昧对象(可能有多个),现在要把他们配情侣,最多能配多少对?(即,寻找最大匹配数)

说明:

  1. 边表示暧昧关系
    注意:
  2. 不能搞基哦
  3. 不能脚踏多只船

请添加图片描述
先从B1看起,他与G2有暧昧,那么先暂时他们配成一对。
注意: 这里突出了先到先得

请添加图片描述
再看B2,B2也可G2纠缠不清,那么我们看G2现在有男友吗?有的,是B1。那B1有没有其他暧昧对象呢?花心男果然是花心男,还有一个G4,同时,G4还没有安排对象。那么把B1和G4配成一对。

注意: 这里突出了能让则让
请添加图片描述
再接着,我们看B3,他这G1直接配对就好。

最后我们看B4,他的暧昧对象是G4,但是G4现在已经有男友了。按照之前的思路,往前到,看看能不能让一让的。发现没法让,所以B4只能单着了。
同时,G3也只能单着。

注意: 这里依然是能让则让,让不了也没法

请添加图片描述
至此,找到一个了最大匹配,但是最大匹配不是固定的。如果从girls这边开始或者从B4开始情况可能就不一样了。但是最大匹配数是一样的。

1.2.3 代码实现

int M,N; // M,N 分表表示左右则集合的元素个数
int Map[MAXM][MAXN]; // 邻接矩阵存图
int p[MAXN]; // 记录当前右侧元素所对应的左侧元素
bool vis[MAXN]; // 记录右侧元素是否已被访问过

bool match(int i){
    for(int j=1;j<=N;++j){ 
        // 有边且未访问
        if(Map[i][j]&&!vis[j]){ 
            vis[j] = true; // 记录访问过
            // 无匹配 或者 原匹配左侧元素可以找到新的匹配
            if(p[j]==0 || match(p[j])){ 
                p[j]=i; // 当前左侧元素成为当前右侧元素的新匹配
                return true // 返回匹配成功
            }
        }
    }
    return false;
}

int Hungarian(){
    int cnt =0;
    for(int i=1; i<=N; ++i){
        memset(vis,false,sizeof(vis)); // 重置vis数组
        if(match(i)) cnt++;
    }
    return cnt
}

1.3 最小点覆盖问题

另外一个关于二分图的问题是求最小点覆盖:我们想找到最少的一些点,使二分图所有的边都至少有一个端点在这些点之中。倒过来说就是,删除包含这些点的边,可以删掉所有边。

20240424115504

(König定理):

一个二分图中的最大匹配数等于这个图中的最小点覆盖数。

1.4 应用

1.4.1 案例一

题目:
面对OIBH组织的嚣张气焰, 柯南决定深入牛棚, 一探虚实.
他经过深思熟虑, 决定从OIBH组织大门进入…
OIBH组织的大门有一个很神奇的锁.
锁是由M*N个格子组成, 其中某些格子凸起(灰色的格子). 每一次操作可以把某一行或某一列的格子给按下去.

20240424115246

如果柯南能在组织限定的次数内将所有格子都按下去, 那么他就能够进入总部. 但是OIBH组织不是吃素的, 他们的限定次数恰是最少次数.
请您帮助柯南计算出开给定的锁所需的最少次数.

读入/Input:

第一行 两个不超过100的正整数N, M表示矩阵的长和宽
以下N行 每行M个数 非0即1 1为凸起方格

输出/Output:

一个整数 所需最少次数


如果我们把样例的矩阵,转化为二分图的形式,是这样的:

20240424115336

按下一行或一列,其实就是删掉与某个点相连的所有边。现在要求最少的操作次数,想想看,这不就是求最小点覆盖数吗?所以直接套匈牙利算法即可。代码略。

参考

  1. https://zhuanlan.zhihu.com/p/96229700
  2. https://zhuanlan.zhihu.com/p/62981901

相关推荐

  1. 算法】字符串匹配算法

    2024-04-24 14:54:03       58 阅读
  2. 算法-KMP匹配

    2024-04-24 14:54:03       43 阅读
  3. 匹配算法 python

    2024-04-24 14:54:03       21 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-24 14:54:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-24 14:54:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-24 14:54:03       82 阅读
  4. Python语言-面向对象

    2024-04-24 14:54:03       91 阅读

热门阅读

  1. ros的master和apollo的cyber的异同

    2024-04-24 14:54:03       29 阅读
  2. windows10 下 wsl + ubuntu + cups 安装使用

    2024-04-24 14:54:03       32 阅读
  3. 从零开始的机器学习之旅:探索Sklearn基础教程

    2024-04-24 14:54:03       36 阅读
  4. PHP中的错误处理机制是怎样的?

    2024-04-24 14:54:03       75 阅读
  5. 如何根据元素的位置关系来调整 CSS 样式

    2024-04-24 14:54:03       31 阅读
  6. PostCSS概述

    2024-04-24 14:54:03       31 阅读
  7. Ajax的请求响应

    2024-04-24 14:54:03       44 阅读
  8. 【无标题】远程链接服务实战

    2024-04-24 14:54:03       186 阅读