int vis[maxn]; booldfs(int u, int d){ vis[u] = d; for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (vis[v] == d) return0; if (vis[v] == -1 && !dfs(v, d ^ 1)) return0; } return1; }
structEdge { int to, next; } e[maxm * 2]; int c1, head[maxn]; inlinevoidadd_edge(int u, int v){ e[c1].to = v; e[c1].next = head[u]; head[u] = c1++; }
int I, vis[maxn], g[maxn]; booldfs(int u){ for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (vis[v] == I) continue; vis[v] = I; if (!g[v] || dfs(g[v])) return g[v] = u, 1; } return0; }
int ans; intmain(){ fill(head, head + maxn, -1); ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m >> k; for (int i = 1; i <= k; ++i) { int x, y; cin >> x >> y; add_edge(x, y + n); add_edge(y + n, x); } for (int i = 1; i <= n; ++i) vis[i] = ++I, ans += dfs(i); cout << ans << "\n"; return0; }
vector<int> ans; bool vis[maxn]; int bl[maxn]; // bl[u] = 0 是左部点,bl[u] = 1 是右部点 voidDfs(int u, int f){ vis[u] = 1; if (bl[u] ^ f) ans.push_back(u); for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to, w = e[i].w; if (w == f && !vis[v]) Dfs(v, f); } }
#include<iostream> #include<vector> #define ll long long #define maxn 510 #define INF 100000000000000000 usingnamespacestd; int n, m;
ll a[maxn][maxn];
ll lx[maxn], ly[maxn], slack[maxn]; bool vis[maxn]; int g[maxn], pre[maxn]; voidbfs(int u){ int x, y = 0, py = 0; g[y] = u; fill(pre, pre + maxn, 0); fill(slack, slack + maxn, INF); do { x = g[y]; vis[y] = 1; ll d = INF; for (int i = 1; i <= n; ++i) { if (vis[i]) continue; if (slack[i] > lx[x] + ly[i] - a[x][i]) slack[i] = lx[x] + ly[i] - a[x][i], pre[i] = y; if (slack[i] < d) d = slack[i], py = i; } for (int i = 0; i <= n; ++i) if (vis[i]) lx[g[i]] -= d, ly[i] += d; else slack[i] -= d; y = py; } while (g[y]); while (y) g[y] = g[pre[y]], y = pre[y]; }
ll KM(){ for (int i = 1; i <= n; ++i) g[i] = lx[i] = ly[i] = 0; for (int i = 1; i <= n; ++i) fill(vis, vis + maxn, 0), bfs(i); ll ans = 0; for (int i = 1; i <= n; ++i) ans += a[g[i]][i]; return ans; }
cin >> n >> m; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) a[i][j] = -INF; for (int i = 1; i <= m; ++i) { int x, y, z; cin >> x >> y >> z; a[x][y] = z; } cout << KM() << "\n"; for (int i = 1; i <= n; ++i) cout << g[i] << " \n"[i == n]; return0; }
#include<iostream> #include<algorithm> #define maxn 1010 #define maxm 2010 #define ll long long usingnamespacestd;
int n, m;
structEdge { int fr, to, next; } e[maxm * 2]; int c1, head[maxn], du[maxn]; inlinevoidadd_edge(int u, int v){ e[c1].fr = u; e[c1].to = v; e[c1].next = head[u]; head[u] = c1++; }
int col[maxn][maxn], ans[maxm]; voidchange(int u, int x, int y){ if (col[u][x] == -1) return col[u][y] = -1, void(); int i = col[u][x], v = e[i].to; change(v, y, x); ans[i / 2 + 1] = y; col[u][y] = i; col[v][y] = i ^ 1; }
cin >> n >> m; for (int i = 1; i <= m; ++i) { int x, y; cin >> x >> y; add_edge(x, y); add_edge(y, x); ++du[x]; ++du[y]; } fill(col[0], col[0] + maxn * maxn, -1); for (int o = 0; o < c1; o += 2) { if (ans[o / 2 + 1]) continue; int u = e[o].fr, v = e[o].to, lu = n, lv = n, l; for (int i = n; i; --i) { if (col[u][i] == -1) lu = i; if (col[v][i] == -1) lv = i; } if (lu < lv) change(v, lu, lv); elseif (lu > lv) change(u, lv, lu); l = min(lu, lv); ans[o / 2 + 1] = l; col[u][l] = o; col[v][l] = o ^ 1; } cout << *max_element(du + 1, du + n + 1) << "\n"; for (int i = 1; i <= m; ++i) cout << ans[i] << "\n"; return0; }
Hall 定理
令左部点为 $X$,右部点为 $Y$,不妨令 $|X|<|Y|$
定义 $M(X)$ 为与 $X$ 相连的点的点集
Hall 定理:一个二分图存在完美匹配的充要条件是对于任意一个 $x\subseteq X$,都有 $|M(x)|\ge |x|$