acwing算法基础之搜索与图论--匈牙利算法求二分图的最大匹配数

目录

  • [1 基础知识](#1 基础知识)
  • [2 模板](#2 模板)
  • [3 工程化](#3 工程化)

1 基础知识

二分图中的最大匹配数:从二分图中选择一些边(这些边连接集合A和集合B,集合A中结点数目为n1,集合B中结点数目为n2),设为集合S,其中任意两条边不共用一个结点。求集合S的最大元素数目,即二分图中的最大匹配数。

匈牙利算法的关键步骤:

  1. 初始化匹配数组match1\~n2 = 0。其中matchb = a,表示集合B中的结点b匹配了集合A中的结点a。
  2. 遍历集合A中的每一个结点a:初始化状态数组st1\~n2 = false,其中stb = false表示集合B中的结点b没有被访问。然后,find(x),如果它返回true,那么答案加1。
cpp 复制代码
bool find(int a) {//a为集合A中的结点
	for (auto b : g[x]) {
		if (!st[b]) {//如果结点b没有被访问
			st[b] = true;
			if (match[b] == 0 || find(match[b])) { //如果结点b没有被匹配,或者结点b匹配了的结点可以找到新的
				match[b] = a;
				return true;
			}
		}
	}
	return false;
}
  1. 最终返回答案,即为该二分图的最大匹配数。

2 模板

cpp 复制代码
int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过

bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }

    return false;
}

// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{
    memset(st, false, sizeof st);
    if (find(i)) res ++ ;
}

3 工程化

题目1:求二分图的最大匹配。

cpp 复制代码
#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

const int N = 510;
int n1, n2, m;
vector<vector<int>> g(N);
int match[N];
bool st[N];

bool find(int a) {
    for (auto b : g[a]) {
        if (!st[b]) {
            st[b] = true;
            if (match[b] == 0 || find(match[b])) {
                match[b] = a;
                return true;
            }
        }
    }
    return false;
}

int main() {
    cin >> n1 >> n2 >> m;
    int a, b;
    while (m--) {
        cin >> a >> b;
        g[a].emplace_back(b);
    }
    
    int res = 0;
    for (int i = 1; i <= n1; ++i) {
        memset(st, 0, sizeof st);
        if (find(i)) res++;
    }
    
    cout << res << endl;
    
    return 0;
}
相关推荐
I_belong_to_jesus9 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Code_Solitude16 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司16 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP18 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
思麟呀19 小时前
背包DP(01背包+完全背包)
c++·算法
笑容掩饰我的失落20 小时前
区块链从小白到精通(七):Solidity 语法精讲——数据类型、函数、修饰器与事件
算法·区块链·php·智能合约·哈希算法
Pniubi21 小时前
力扣24. 两两交换链表中的节点(递归)
算法·leetcode·链表
꧁细听勿语情꧂21 小时前
直接选择排序,堆排序,冒泡排序,递归快速排序、hoare版本、挖坑法、lomuto前后指针,非递归快速排序
c语言·开发语言·数据结构·算法
俊俊几年的1 天前
动态规划(Dynamic Programming)详解:从入门到 LeetCode Hot 100
linux·c++·算法·leetcode·嵌入式·动态规划·c