zoukankan      html  css  js  c++  java
  • 【UOJ #79】一般图最大匹配 带花树模板

    http://uoj.ac/problem/79
    带花树模板,做法详见cyb的论文或fhq的博客。
    带花树每次对一个未盖点bfs增广,遇到奇环就用并查集缩环变成花(一个点),同时记录每个点的Next(表示匹配),状态s(-1表示这个点没访问过,0表示这个点可以搜另一条相邻的未盖边,1表示这个点不能用于搜另一条相邻的未盖边),pre数组(u原先的匹配是Next[u],增广时u的匹配断掉了,u就与pre[u]进行匹配,即Next[u]=pre[u],Next[pre[u]]=u)。从一个点pre和Next交替的走出来的路径表示一条通往bfs树的根的路径(用于找到另一个未盖点后进行增广)。
    时间复杂度(O(n^3))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 503;
    const int M = 130003;
    
    struct node {int nxt, to;} E[M << 1];
    int Next[N], cnt = 0, point[N], n, m, qu[N], s[N], pre[N], fa[N];
    
    void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}
    
    int find(int x) {return fa[x] == x ? x : (fa[x] = find(fa[x]));}
    
    int tim = 0, vis[N];
    int getlca(int u, int v) {
    	++tim;
    	while (true) {
    		if (u) {
    			if (vis[u] == tim) return u;
    			vis[u] = tim;
    			u = find(pre[Next[u]]);
    		}
    		swap(u, v);
    	}
    }
    
    int p, q;
    void blossom(int u, int v, int lca) {
    	while (find(u) != lca) {
    		pre[u] = v;
    		v = Next[u];
    		if (s[v] == 1) {s[v] = 0; if (++q == N) q = 0; qu[q] = v;}
    		if (fa[v] == v) fa[v] = lca;
    		if (fa[u] == u) fa[u] = lca;
    		u = pre[v];
    	}
    }
    
    int match(int x) {
    	memset(s + 1, -1, sizeof(int) * n);
    	for (int i = 1; i <= n; ++i) fa[i] = i;
    	int u, v; p = 0; q = 1;
    	s[qu[1] = x] = 0; pre[x] = 0;
    	
    	while (p != q) {
    		if (++p == N) p = 0; u = qu[p];
    		for (int i = point[u]; i; i = E[i].nxt) {
    			v = E[i].to;
    			if (s[v] == -1) {
    				s[v] = 1; pre[v] = u;
    				if (!Next[v]) {
    					int last;
    					while (u) {
    						last = Next[u];
    						Next[u] = v; Next[v] = u;
    						u = pre[v = last];
    					}
    					return 1;
    				}
    				s[Next[v]] = 0; if (++q == N) q = 0; qu[q] = Next[v];
    			} else if (s[v] == 0 && find(u) != find(v)) {
    				int lca = getlca(fa[u], fa[v]);
    				blossom(u, v, lca);
    				blossom(v, u, lca);
    			}
    		}
    	}
    	
    	return 0;
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	int u, v;
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d", &u, &v);
    		ins(u, v); ins(v, u);
    	}
    	
    	int ans = 0;
    	for (int i = 1; i <= n; ++i)
    		if (!Next[i])
    			ans += match(i);
    	
    	printf("%d
    ", ans);
    	for (int i = 1; i <= n; ++i)
    		printf("%d ", Next[i]);
    	return 0;
    }
    
  • 相关阅读:
    【POJ 2987】Firing (最小割-最大权闭合子图)
    -网络流经典模型
    【bzoj 3299】 [USACO2011 Open]Corn Maze玉米迷宫(最短路)
    【POJ 3623】 Best Cow Line, Gold (后缀数组)
    题表-各种生成树
    yield 生成器的运行机制
    numpy.random.shuffle(x)的用法
    Softmax回归(Softmax Regression
    softmax 函数
    极大似然估计的朴素理解
  • 原文地址:https://www.cnblogs.com/abclzr/p/6555301.html
Copyright © 2011-2022 走看看