【XSY2774】学习 带花树
题目描述
给你一个图,求最大匹配。
边的描述方式很特殊,就是一次告诉你\(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】学习 带花树的更多相关文章
- URAL 1099. Work Scheduling (一般图匹配带花树)
1099. Work Scheduling Time limit: 0.5 secondMemory limit: 64 MB There is certain amount of night gua ...
- HDU 4687 Boke and Tsukkomi (一般图匹配带花树)
Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Othe ...
- P6113-[模板]一般图最大匹配【带花树】
正题 题目链接:https://www.luogu.com.cn/problem/P6113 题目大意 给出一张无向图,求最大匹配. \(1\leq n\leq 10^3,1\leq m\leq 5\ ...
- [转]带花树,Edmonds's matching algorithm,一般图最大匹配
看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...
- HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力
一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...
- 【Learning】带花树——一般图最大匹配
一般图最大匹配--带花树 问题 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. 这个问题的退化版本就是二分图最大匹配. 由于二分图中不存在奇环,偶环对最大匹配并无 ...
- 【learning】一般图最大匹配——带花树
问题描述 对于一个图\(G(V,E)\),当点对集\(S\)满足任意\((u,v)\in S\),均有\(u,v\in V,(u,v)\in E\),且\(S\)中没有点重复出现,我们称\(S\) ...
- [BZOJ]4405: [wc2016]挑战NPC(带花树)
带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...
- HDU 4687 Boke and Tsukkomi (一般图最大匹配)【带花树】
<题目链接> 题目大意: 给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的. 解题分析: 所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义.那怎样 ...
随机推荐
- long double
long double 输入输出 scanf("%Lf",&a); printf("%.20Lf\n",a);
- centos7 安装phpmyadmin
1.先安装epel,不然安装pgpmyadmin时会出现找不到包. yum install epel-release rpm -ivh http://rpms.famillecollet.com/en ...
- Elasticsearch之配置详解
Cluster 集群名称,默认为elasticsearch: cluster.name: elasticsearch 设置一个节点的并发数量,有两种情况,一种是在初始复苏过程中: cluster.ro ...
- pinpoint vs druid
主流Java数据库连接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid) - ppjj - 博客园 https://www.cnblogs.com/nizuimeiabc1/ ...
- MySQL 性能调优之SQL
原文:http://bbs.landingbj.com/t-0-245451-1.html 对于SQL的优化,我们主要提供调整执行计划.优化SQL的方法有:缩短访问的路径.尽早过滤数据.尽可能减少排序 ...
- 在linux上安装Scala详细步骤
scala在linux安装很简单,就是下载,解压,配置环境变量,source一下成功. 提君博客原创 >>提君博客原创 http://www.cnblogs.com/tijun/ < ...
- php变量详解
变量是用于存储信息的"容器". 定义一个变量的语法: $变量名 = 值; 使用变量的例子: <?php $x=5; $y=6; $z=$x+$y; echo $z; ?> ...
- C# Note20: 制作延时改变显示的标题栏
前言 在使用wpf构建一个窗体时,其中有这样一个功能,在保存数据或加载数据时,我们希望在改变标题栏的显示以标志当前保存成功的状态或者加载数据的名称信息,而且标题信息更新显示几秒后,再恢复到默认的状态. ...
- TextView不用ScrollViewe也可以滚动的方法
转自:http://www.jb51.net/article/43377.htm android TextView不用ScrollViewe也可以滚动的方法. TextView textview = ...
- php的amqp扩展 安装(windows) rabbitmq学习篇
因为RabbitMQ是由erlang语言实现的,所以先要安装erlang环境erlang 下载安装 http://www.erlang.org/download.htmlrabbitmq 下载安装 h ...