带花树裸题,感觉带花树强强……不会的勿看此文,解释的可能不对,只是给自己看的!!!如题,带花树即为求一般图最大匹配算法(匈牙利与dinic为二分图最大匹配)。推荐论文:2015年《浅谈图的匹配算法及其应用》(长郡中学 ——陈胤伯)。论文当中有对于带花树算法的详细解析,在这里只想记录一下算法的基本流程:
——————————————————————————
\(id\) : 记录一个点为奇点/偶点(0偶1奇)。
\(fa\) : 并查集记录一个点属于哪一个点为根的花。
——————————————————————————
我们对于每一个没有匹配到的点进行 bfs,默认该点为一个偶点。
当我们遍历到一个未访问过的点(在此次bfs中):
-若该点未匹配:
Yes!我们找到了一条新的增广路。顺着 \( pre \) 数组的指引反向增广,修改匹配的对象。(当前点为\(x\), \(y = pre[x]\),\(z = match[y]\), 则应使 \(x\), \(y\) 成为匹配边,\(z\) 点继续增广(过程同上,一直到增广不下去了为止))。
-若该点已匹配:
将它的匹配点标记为偶点,推进队列。
遍历到一个访问过的点(在此次bfs中):
-若该点是一个奇点:
找到的是一个偶环,无视。
-若该点是一个偶点:
如果这两个点本来就在同一朵花中,无视。否则进行缩花。我们找到这两点在bfs树上的 lca: \(k\);将这两点之间连上边从\(x\) 开始向上遍历所有的匹配边,找到一朵花的根节点就修改其花根为 \(k\); 若找到的点有匹配点,则将匹配点也标记为偶点并压入队列。
总之是个玄学算法……
#include <bits/stdc++.h> using namespace std; #define maxn 300000 int n, m, match[maxn]; int pre[maxn], id[maxn]; int timer, fa[maxn], ans; int vis[maxn]; queue <int> q; struct edge { int cnp = 1, head[maxn], to[maxn], last[maxn]; void add(int u, int v) { to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++; to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++; } }E1; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) k = -1; c = getchar(); } while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar(); return x * k; } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } void Clear(queue<int> &q) { queue <int> empty; swap(empty, q); } int LCA(int x, int y) { timer ++; while(vis[x] != timer) { if(x) { x = find(x); if(vis[x] == timer) return x; vis[x] = timer; if(match[x]) x = find(pre[match[x]]); else x = 0; } swap(x, y); } return x; } void Change(int x, int y, int k) { while(find(x) != k) { pre[x] = y; int z = match[x]; if(id[z] == 1) id[z] = 0, q.push(z); if(find(z) == z) fa[z] = k; if(find(x) == x) fa[x] = k; y = z; x = pre[y]; } } bool bfs(int u) { for(int i = 1; i <= n; i ++) id[i] = -1, fa[i] = i; Clear(q); q.push(u); id[u] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = E1.head[u]; i; i = E1.last[i]) { int v = E1.to[i]; if(id[v] == -1) { pre[v] = u; id[v] = 1; if(match[v]) { id[match[v]] = 0; q.push(match[v]); continue; } int last, t, now = v; while(now) { t = pre[now]; last = match[t]; match[t] = now, match[now] = t; now = last; } return 1; } else if(!id[v] && find(u) != find(v)) { int lca = LCA(u, v); Change(u, v, lca), Change(v, u, lca); } } } return 0; } int main() { n = read(), m = read(); for(int i = 1; i <= m; i ++) { int x = read(), y = read(); E1.add(x, y); } for(int i = 1; i <= n; i ++) if(!match[i] && bfs(i)) ans ++; printf("%d\n", ans); for(int i = 1; i <= n; i ++) printf("%d ", match[i]); return 0; }
原文地址:https://www.cnblogs.com/twilight-sx/p/9244779.html