首页 技术 正文
技术 2022年11月21日
0 收藏 365 点赞 2,523 浏览 2205 个字

  带花树裸题,感觉带花树强强……不会的勿看此文,解释的可能不对,只是给自己看的!!!如题,带花树即为求一般图最大匹配算法(匈牙利与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 = , 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 = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', 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 = ;
}
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] == ) id[z] = , 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 = ; i <= n; i ++) id[i] = -, fa[i] = i;
Clear(q); q.push(u); id[u] = ;
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] == -)
{
pre[v] = u; id[v] = ;
if(match[v])
{
id[match[v]] = ; 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 ;
}
else if(!id[v] && find(u) != find(v))
{
int lca = LCA(u, v);
Change(u, v, lca), Change(v, u, lca);
}
}
}
return ;
}int main()
{
n = read(), m = read();
for(int i = ; i <= m; i ++)
{
int x = read(), y = read();
E1.add(x, y);
}
for(int i = ; i <= n; i ++) if(!match[i] && bfs(i)) ans ++;
printf("%d\n", ans);
for(int i = ; i <= n; i ++) printf("%d ", match[i]);
return ;
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,027
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,518
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,365
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,146
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,780
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,857