一般图最大匹配带花树

参考博客:http://blog.sina.com.cn/s/blog_95ec9e7401018bga.html

     https://www.cnblogs.com/owenyu/p/6858508.html

用Dinic实现的二分图匹配的时间复杂度其实是O(M*N^0.5),这也许能够解释为什么一般网络流算法比Hungry要快了。

另外,带花树算法的正确性的证明比较困难;而其时间复杂度是可以做到O(M*N^0.5)的

简述一下“带花树”算法吧:

它的核心思想还是找增广路。假设已经匹配好了一堆点,我们从一个没有匹配的节点s开始,使用BFS生成搜索树。每当发现一个节点u,如果u还没有被匹配,那么就可以进行一次成功的增广;否则,我们就把节点u和它的配偶v一同接到树上,之后把v丢进队列继续搜索。我们给每个在搜索树上的点一个类型:S或者T。当u把它的配偶v扔进队列的时候,我们把u标记为T型,v标记为S型。于是,搜索树的样子是这样的:

其中,黑色竖线相连的两个点是已经匹配好的,蓝色斜线表示两个点之间有边,但是没有配对。T型的用红色,S型的用黑色。

这里有个小问题:一个S型点d在某一步扩展的时候发现了点u,如果u已经在搜索树上了(即,出现了环),怎么办?

我们规定,如果u的类型是T型,就无视这次发现;(这意味着我们找到了一个长度为偶数的环,直接无视)

如果连出来的边是指向T型点的,就无视这个边。否则,我们找到了一个长度为奇数的环,就要进行一次“缩花”的操作!所谓缩花操作,就是把这个环缩成一个点。

这个图缩花之后变成了5个点(一个大点,或者叫一朵花,加原来的4个点):

缩点完成之后,还要把原来环里面的T型点统统变成S型点,之后扔到队列里去。

为什么能缩成一个点呢?我们看一个长度为奇数的环(例如上图中的s-b-d-j-f-c-a-),如果我们能够给它中的任意一个点找一个出度(配偶),那么环中的其他点正好可以配成对,这说明,每个点的出度都是等效的。例如,假设我们能够给图中的点d另找一个配偶(例如d'好了),那么,环中的剩下6个点正好能配成3对,一个不多,一个不少(算上d和d'一共4对刚刚好)。

这就是我们缩点的思想来源。有一个劳苦功高的计算机科学家证明了:缩点之前和缩点之后的图是否有增广路的情况是相同的。

缩起来的点又叫一朵花(blossom).

注意到,组成一朵花的里面可能嵌套着更小的花。

当我们最终找到一条增广路的时候,要把嵌套着的花层层展开,还原出原图上的增广路出来。

嗯,现在你对实现这个算法有任何想法吗?

天啊,还要缩点……写死谁。。。。。。

我一开始也是这么想的。

我看了一眼网上某个大牛的程序,之后结合自己的想法,很努力地写出了一个能AC的版本。

实现的要点有什么呢?

首先,我们不“显式”地表示花。我们记录一个Next数组,表示最终增广的时候的路径上的后继。同时,我们维护一个并查集,表示每个点现在在以哪个点为根的花里(一个花被缩进另一朵花之后就不算花了)。还要记录每个点的标记。

主程序是一段BFS。对于每个由x发展出来的点y,分4种情况讨论:

1。xy是配偶(不说夫妻,这是非二分图。。。)或者xy现在是一个点(在一朵花里):直接无视

2。y是T型点:直接无视

3。y目前单身:太好了,进行增广!

4。y是一个S型点:缩点!缩点!

缩点的时候要进行的工作:

1。找x和y的LCA(的根)p。找LCA可以用各种方法。。。直接朴素也行。

2。在Next数组中把x和y接起来(表示它们形成环了!)

3。从x、y分别走到p,修改并查集使得它们都变成一家人,同时沿路把Next数组接起来。

Next数组很奇妙。每时每刻,它实际形成了若干个挂在一起的双向链表来表示一朵花内部的走法。

下面以uoj79,给出一般图匹配模板

代码:

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int read() {
 7     int x=0,f=1;
 8     char c=getchar();
 9     for (;!isdigit(c);c=getchar()) if (c==‘-‘) f=-1;
10     for (;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
11     return x*f;
12 }
13 const int maxn=505;
14 const int maxm=maxn*maxn*2;
15 int n,m,que[maxm],ql,qr,pre[maxn],tim=0;
16 struct edge {
17     int v,nxt;
18 } e[maxm];
19 int h[maxn],tot=0;
20 int match[maxn],f[maxn],tp[maxn],tic[maxn];
21 int find(int x) {
22     return f[x]==x?f[x]:f[x]=find(f[x]);
23 }
24 void add(int u,int v) {
25     e[++tot]=(edge){v,h[u]};
26     h[u]=tot;
27 }
28 int lca(int x,int y) {
29     for (++tim;;swap(x,y)) if (x) {
30         x=find(x);
31         if (tic[x]==tim) return x; else tic[x]=tim,x=pre[match[x]];
32     }
33 }
34 void shrink(int x,int y,int p) {
35     while (find(x)!=p) {
36         pre[x]=y,y=match[x];
37         if (tp[y]==2) tp[y]=1,que[++qr]=y;
38         if (find(x)==x) f[x]=p;
39         if (find(y)==y) f[y]=p;
40         x=pre[y];
41     }
42 }
43 bool aug(int s) {
44     for (int i=1;i<=n;++i) f[i]=i;
45     memset(tp,0,sizeof tp),memset(pre,0,sizeof pre);
46     tp[que[ql=qr=1]=s]=1; // 1: type A ; 2: type B
47     int t=0;
48     while (ql<=qr) {
49         int x=que[ql++];
50         for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) {
51             if (find(v)==find(x) || tp[v]==2) continue;
52             if (!tp[v]) {
53                 tp[v]=2,pre[v]=x;
54                 if (!match[v]) {
55                     for (int now=v,last,tmp;now;now=last) {
56                         last=match[tmp=pre[now]];
57                         match[now]=tmp,match[tmp]=now;
58                     }
59                     return true;
60                 }
61                 tp[match[v]]=1,que[++qr]=match[v];
62             } else if (tp[v]==1) {
63                 int l=lca(x,v);
64                 shrink(x,v,l);
65                 shrink(v,x,l);
66             }
67         }
68     }
69     return false;
70 }
71 int main() {
72 #ifndef ONLINE_JUDGE
73     freopen("test.in","r",stdin);
74     freopen("my.out","w",stdout);
75 #endif
76     n=read(),m=read();
77     for (int i=1;i<=m;++i) {
78         int x=read(),y=read();
79         add(x,y),add(y,x);
80     }
81     int ans=0;
82     for (int i=1;i<=n;++i) ans+=(!match[i] && aug(i));
83     printf("%d\n",ans);
84     for (int i=1;i<=n;++i) printf("%d ",match[i]);
85     puts("");
86     return 0;
87 }

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11483184.html

时间: 2024-11-08 01:11:58

一般图最大匹配带花树的相关文章

HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力

一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 如果C2+2==C1则这条边再某个最大匹配中 Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 649    Accepted Submission(s): 202

poj 3020 一般图最大匹配 带花树开花算法

题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w <= 10 思路: 最小边覆盖=|V|-最大匹配 一般图最大匹配,带花树开花算法 /*poj 3020 一般图最大匹配 带花树开花算法 题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w &l

ZOJ 3316 Game 一般图最大匹配带花树

一般图最大匹配带花树: 建图后,计算最大匹配数. 如果有一个联通块不是完美匹配,先手就可以走那个没被匹配到的点,后手不论怎么走,都必然走到一个被匹配的点上,先手就可以顺着这个交错路走下去,最后一定是后手没有路可走,因为如果还有路可走,这一条交错路,就是一个增广路,必然有更大的匹配. Game Time Limit: 1 Second      Memory Limit: 32768 KB Fire and Lam are addicted to the game of Go recently.

【UOJ 79】 一般图最大匹配 (?带花树开花)

从前一个和谐的班级,所有人都是搞OI的.有 n 个是男生,有 0 个是女生.男生编号分别为 1,-,n. 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽.每个人至多属于一个小组. 有若干个这样的条件:第 v 个男生和第 u 个男生愿意组成小组. 请问这个班级里最多产生多少个小组? 输入格式 第一行两个正整数,n,m.保证 n≥2. 接下来 m 行,每行两个整数 v,u 表示第 v 个男生和第 u 个男生愿意组成小组.保证 1≤v,u≤n,保证 v≠u,保证同一个条

Work Scheduling URAL - 1099 一般图最大匹配带花树

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <string> using namespace std; const int MAXN = 250; int N; //点的个数,点的编号从1到N bool Graph[MAXN][MAXN]; int Match[MAXN]; bool InQueue[MAXN],I

zoj3316【一般图最大匹配 带花树开花】

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3726 算法见:http://fanhq666.blog.163.com/blog/static/8194342620120304463580/ 题意:棋盘上有n个点,现在两个人轮流在移除一个子,每次移除的子距离上次移除的子曼哈顿距离小于L.最后不能移除的人输. 分析:将距离小于L的点连边.如果一个连通块不是是完备匹配,先手一定可以让自己走到一个没有匹配的点上,然后后手就

kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数 König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选

URAL 1099. Work Scheduling 一般图匹配带花树

一般图匹配带花树模版题: 将奇环缩成圈(Blossom),然后找增广路..... 1099. Work Scheduling Time limit: 0.5 second Memory limit: 64 MB There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to sche

HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4

http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极大匹配中都必然有si或ti至少一个点被匹配,当在图中去掉si,ti两个点时,匹配数会损失一个或两个. 如果损失两个,就说明在极大匹配中这两个点分别连接不同的边,于是边i是无用的 所以总体思路:一般图匹配求出最大匹配数cnt0,分别试着去掉每条边的端点,再次匹配,匹配数如果小于cnt0-1,则这条边无