#include<bits/stdc++.h> usingnamespace std; structEdge { int v, w, nxt; }edge[2500000 + 10]; int head[12000 + 10], idx = 1; voidadd(int u, int v, int w){ edge[++idx] = { v,w,head[u] }; head[u] = idx; } voidaddedge(int u, int v, int w){ add(u, v, w); add(v, u, 0); } int h[12000 + 10], more[12000 + 10], g[12000 + 10]; struct_ { booloperator()(int a, int b){ return h[a] < h[b]; } }; priority_queue<int, vector<int>, _> pq; bool vis[12000 + 10]; voidbfs(int t){ memset(h, 0x3f, sizeof h); queue<int>q; h[t] = 0; q.push(t); while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i; i = edge[i].nxt) if (edge[i ^ 1].w && h[edge[i].v] > h[now] + 1) h[edge[i].v] = h[now] + 1, q.push(edge[i].v); } } voidpush(int now, int s, int t){ for (int i = head[now]; i; i = edge[i].nxt) { if (edge[i].w && h[edge[i].v] + 1 == h[now]) { int flow = min(more[now], edge[i].w); more[edge[i].v] += flow; more[now] -= flow; edge[i].w -= flow; edge[i ^ 1].w += flow; if (edge[i].v != s && edge[i].v != t && !vis[edge[i].v]) vis[edge[i].v] = 1, pq.push(edge[i].v); if (more[now] == 0) return; } } } voidrelabel(int now){ h[now] = INT_MAX; for (int i = head[now]; i; i = edge[i].nxt) if (edge[i].w && h[edge[i].v] + 1 < h[now]) h[now] = h[edge[i].v] + 1; } inthlpp(int n, int s, int t){ bfs(t); if (h[s] == 0x3f3f3f3f) return0; h[s] = n; for (int i = 1; i <= n; ++i) if (h[i] ^ 0x3f3f3f3f) g[h[i]]++; for (int i = head[s]; i; i = edge[i].nxt) if (int w = edge[i].w; w) edge[i].w -= w, edge[i ^ 1].w += w, more[s] -= w, more[edge[i].v] += w, edge[i].v != s && edge[i].v != t && !vis[edge[i].v] ? vis[edge[i].v] = 1, pq.push(edge[i].v) : void(); while (!pq.empty()) { int now = pq.top(); pq.pop(); vis[now] = 0; push(now, s, t); if (more[now]) if ((h[now] ^ 0x3f3f3f3f)) { if (!--g[h[now]]) for (int i = 1; i <= n; i++) if (i != s && i != t && h[i] > h[now] && h[i] < n + 1) h[i] = n + 1; relabel(now); ++g[h[now]], pq.push(now), vis[now] = 1; } } return more[t]; } int n, m, e, s, t; signedmain(){ cin.tie(0)->sync_with_stdio(false); cin >> n >> m >> e; s = n + m + 1; t = n + m + 2; for (int i = 1, u, v; i <= e; ++i) cin >> u >> v, addedge(u, n + v, 1); for (int i = 1; i <= n; ++i) addedge(s, i, 1); for (int i = 1; i <= m; ++i) addedge(i + n, t, 1); cout << hlpp(n + m + 2, s, t) << endl; return0; }
二分图最大权匹配
这里我们使用 KM 算法解决 二分图最大权完美匹配 的问题,而我们将一个普通二分图补点补成相等,然后我们将不存在的边权重设为 0,这种情况下,问题就转换成求 最大权完美匹配问题,从而能应用 KM 算法求解。