二分图的最大匹配
C++
二分图的最大匹配
/* * 二分图的最大匹配 * * 先前在介绍二分图时候,我们简述了什么是二分图,以及二分图的充要条件,并学会使用了染色法来判断二分图。 * 此次来介绍二分图的最大匹配。 * * 定义: * 二分图的匹配: * 给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。 * 二分图的最大匹配: * 所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。 * 二分图最大匹配算法: * 二分图最大匹配算法是基于暴力搜索的算法,同时又使用了 st 数组进行记忆化搜索,因而复杂度控制到了 O(NM)。 * * res = 0 * 对集合 U 中的每一个点进行遍历 * for u in U: * 记忆化清空,集合 V * memset(st, false, sizeof st) * 如果点 u 可以找到集合 V 中的点 v 相匹配 (这里匹配指的是 v 之前并未和其他点匹配过, * 或者之前和点 v 匹配的点 u' 可以找到集合中的 v' 配对 -> 这是一个递归的过程 * st 数组,优先剪枝,避免了环形循环) * res += 1 * 当然,这个 memset 是可以条件性优化的,因为当 u find 为 false 的时候,那么 之前 st 标记为 false 的点,仍旧是没有办法给他腾出一条边。 * u find = true, 才需要 memset(st, false, sizeof st)。 * */ #include <iostream> #include <cstring> #include <string> #include <algorithm> using namespace std; const int N = 510, M = 100010; int n1, n2, m; int h[N], e[M], ne[M], idx; int match[N]; bool st[N]; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++; } // 查看 u 能否在不减少 res 的条件下,多加一条边 bool Find(int u) { int v; for (int i = h[u]; ~i; i = ne[i]) { v = e[i]; if (st[v] == false) { st[v] = true; if (match[v] == -1 || Find(match[v])) { match[v] = u; return true; } } } return false; } int main() { // initialize memset(h, -1, sizeof h); memset(ne, -1, sizeof ne); memset(match, -1, sizeof match); idx = 0; // input scanf("%d%d%d", &n1, &n2, &m); while (m -- ) { static int u, v; scanf("%d%d", &u, &v); add(u, v); } // get the max match int res = 0; bool pre = true; for (int i = 1; i <= n1; i ++ ) { if (pre == true) { memset(st, false, sizeof st); } pre = Find(i); if (pre) { res += 1; } } printf("%d\n", res); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)