题目描述

  给你一个图,求最大匹配。

  边的描述方式很特殊,就是一次告诉你\(c_i\)个点:\(d_1,d_2,\ldots,d_{c_i}\),表示这些点两两之间都有连边,也就是说,这是一个团。总共有\(m\)个团。

  记\(s=\sum_{i=1}^mc_i\)。

  \(n,m,s\leq 3000\)

题解

  直接跑带花树的话时间复杂度是\(O(ns^2\alpha(n))\)的,显然会TLE。

  假设每个\(c_i\)都是偶数(如果是奇数就让最后一个点像前面的点连边,然后把这个点去掉)。

  对于每一个团,添加\(k=c_i\)个辅助点,按以下方式连边(红色的为原来的店,蓝色的为辅助点):

  

  易证有\(x\)个红色点和蓝色点匹配时,最大匹配是\(\lfloor\frac{x+k}{2}\rfloor\)。

  (可以先选一个红色点匹配,然后顺时针确定其他红色点,对这个红色点相邻的蓝色点到上一个红色点相邻的蓝色点之间蓝色点个数分类讨论来决定这个红色点连向那个蓝色点。)

  对于每个团,令\(k\)为偶数,然后在跑完带花树后把答案减掉\(\sum k/2\)。

  这样建图的边的个数是\(O(s)\)的。

  时间复杂度:\(O(ns\alpha(n))\)

  (显然\(O(n\alpha(n))\)的并查集常数很大会被卡常。)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
s=c-'0';
while((c=getchar())>='0'&&c<='9')
s=s*10+c-'0';
return s;
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
struct graph
{
int h[6010];
int v[10000010];
int t[10000010];
int n;
void clear()
{
memset(h,0,sizeof h);
n=0;
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
graph g;
int n,m;
int ans;
int c[6010];
int f[6010];
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int link[6010];
int d[6010];
int b[6010];
int q[6010];
int pre[6010];
int head,tail;
void aug(int x)
{
for(int y=pre[x];x;x=pre[y],y=pre[x])
{
link[x]=y;
pre[y]=link[y];
link[y]=x;
}
}
int vis[6010];
int ti=0;
int getlca(int x,int y)
{
ti++;
for(x=find(x),y=find(y);;swap(x,y))
if(x)
{
if(vis[x]==ti)
return x;
vis[x]=ti;
x=find(pre[link[x]]);
}
return 0;
}
void gao(int x,int y,int lca)
{
for(;find(x)!=lca;x=pre[y])
{
pre[x]=y;
y=link[x];
f[x]=lca;
f[y]=lca;
if(d[y])
{
d[y]=0;
q[++tail]=y;
}
}
}
int num;
int bfs(int x)
{
memset(b,0,sizeof b);
for(int i=1;i<=num;i++)
f[i]=i;
head=1,tail=0;
d[x]=0;
b[x]=1;
q[++tail]=x;
int v;
while(tail>=head)
{
x=q[head++];
for(int i=g.h[x];i;i=g.t[i])
if(find(v=g.v[i])==find(x))
continue;
else
{
if(!b[v])
{
pre[v]=x;
b[v]=1;
if(!link[v])
{
aug(v);
return 1;
}
else
{
b[link[v]]=1;
d[v]=1;
d[link[v]]=0;
q[++tail]=link[v];
}
}
else
{
if(!d[v])
{
int lca=getlca(x,v);
gao(x,v,lca);
gao(v,x,lca);
}
}
}
}
return 0;
}
void solve()
{
num=n;
g.clear();
int x,y;
ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
for(int j=1;j<=x;j++)
scanf("%d",&c[j]);
sort(c+1,c+x+1);
x=unique(c+1,c+x+1)-c-1;
if(x&1)
{
for(int j=1;j<x;j++)
{
g.add(c[j],c[x]);
g.add(c[x],c[j]);
}
x--;
}
for(int j=1;j<=x;j++)
{
g.add(num+j,num+j%x+1);
g.add(num+j%x+1,num+j);
}
for(int j=1;j<=x;j++)
{
g.add(c[j],num+j);
g.add(num+j,c[j]);
g.add(c[j],num+j%x+1);
g.add(num+j%x+1,c[j]);
}
ans-=x/2;
num+=x;
}
memset(link,0,sizeof link);
for(int i=1;i<=num;i++)
if(!link[i])
{
if(bfs(i))
ans++;
}
printf("%d\n",ans);
}
int main()
{
open("c");
while(~scanf("%d%d",&n,&m)&&(n||m))
solve();
return 0;
}

【XSY2774】学习 带花树的更多相关文章

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

    1099. Work Scheduling Time limit: 0.5 secondMemory limit: 64 MB There is certain amount of night gua ...

  2. HDU 4687 Boke and Tsukkomi (一般图匹配带花树)

    Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Othe ...

  3. P6113-[模板]一般图最大匹配【带花树】

    正题 题目链接:https://www.luogu.com.cn/problem/P6113 题目大意 给出一张无向图,求最大匹配. \(1\leq n\leq 10^3,1\leq m\leq 5\ ...

  4. [转]带花树,Edmonds's matching algorithm,一般图最大匹配

    看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...

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

    一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...

  6. 【Learning】带花树——一般图最大匹配

    一般图最大匹配--带花树 问题 ​ 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. ​ 这个问题的退化版本就是二分图最大匹配. ​ 由于二分图中不存在奇环,偶环对最大匹配并无 ...

  7. 【learning】一般图最大匹配——带花树

    问题描述 ​ 对于一个图\(G(V,E)\),当点对集\(S\)满足任意\((u,v)\in S\),均有\(u,v\in V,(u,v)\in E\),且\(S\)中没有点重复出现,我们称\(S\) ...

  8. [BZOJ]4405: [wc2016]挑战NPC(带花树)

    带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...

  9. HDU 4687 Boke and Tsukkomi (一般图最大匹配)【带花树】

    <题目链接> 题目大意: 给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的. 解题分析: 所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义.那怎样 ...

随机推荐

  1. 腾讯内推一面C++

    北邮论坛找个腾讯的内推,没想到那么快就安排面试了.第一次面腾讯,写点东西记录一下吧. 面的是位置服务部门. 去了之后HR先给了两张纸,有三道编程题.第一道是求 二进制中1的个数(考察位运算)(剑指of ...

  2. [2018福大至诚软工助教]alpha阶段小结

    [2018福大至诚软工助教]alpha阶段小结 一.得分 1. 冲刺(7次 Scrum) 150分 1)第1篇(25分) 项目 评分标准 各个成员在 Alpha 阶段认领的任务 (6分)视详细程度给分 ...

  3. Applese 的毒气炸弹 G 牛客寒假算法基础集训营4(图论+最小生成树)

    链接:https://ac.nowcoder.com/acm/contest/330/G来源:牛客网 Applese 的毒气炸弹 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262 ...

  4. c语言之字符串和格式化输入输出

    字符串和格式化输入输出 #include<stdio.h> #include<string.h> #define DENSITY 62.4 int main(void) { f ...

  5. vue-cli脚手架安装和webpack-simple模板项目生成

    vue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目. GitHub地址是:https://github.com/vuejs/vue-cli 一. ...

  6. snappy

    Snappy 是一个 C++ 的用来压缩和解压缩的开发包.其目标不是最大限度压缩或者兼容其他压缩格式,而是旨在提供高速压缩速度和合理的压缩率.Snappy 比 zlib 更快,但文件相对要大 % 到 ...

  7. 什么是arp协议?

    转自:https://blog.csdn.net/tigerjibo/article/details/7351992 ARP (Address Resolution Protocol) 是个地址解析协 ...

  8. js 判断一个字符在字符串中出现的次数

    <script type="text/javascript"> var s='djh.doiwe.esd.d.ddd0sdd.d.'; var n=(s.split(' ...

  9. AngularJS路由使用案例

    AngularJS路由使用案例: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...

  10. spring AOP的用法

    AOP,面向切面编程,它能把与核心业务逻辑无关的散落在各处并且重复的代码给封装起来,降低了模块之间的耦合度,便于维护.具体的应用场景有:日志,权限和事务管理这些方面.可以通过一张图来理解下: Spri ...