【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条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的. 解题分析: 所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义.那怎样 ...
随机推荐
- SQL SERVER中的两种常见死锁及解决思路
在sql server中,死锁都与一种锁有关,那就是排它锁(x锁).由于在同一时间对同一个数据库资源只能有一个数据库进程可以拥有排它锁.因此,一旦多个进程都需要获取某个或者同一个数据库资源的排它访问权 ...
- Python-序列化模块-json-62
序列化模块 Eva_J 什么叫序列化——将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化. 比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给? 现在我们能想到 ...
- 295B - Greg and Graph (floyd逆序处理)
题意:给出任意两点之间的距离,然后逐个删除这些点和与点相连的边,问,在每次删除前的所有点对的最短距离之和 分析:首先想到的是floyd,但是如果从前往后处理,复杂度是(500)^4,超时,我们从后往前 ...
- poj2104 主席树裸题
空间大小:n*lgn 复杂度:建树n*lgn 查询lgn #include <cstdio> #include <iostream> #include <algorit ...
- scrapy之环境安装
scrapy之环境安装 在之前我安装了scrapy,但是在pycharm中却无法使用. 具体情况是: 我的电脑上存在多个python,有python2,python3,anaconda,其中anaco ...
- Python之字符串操作
一.字符串特点 内容不可修改 password=' #内容不可修改 二.字符串常用方法 1..strip()方法 去字符串两边的空格和换行符 print(password.strip()) #去掉字符 ...
- Oracle行列转换case when then方法案例
select (select name from t_area where id=areaid) 区域, end) 一月, end) 二月, end) 三月, end) 四月, end) 五月, en ...
- Git本地仓库push至GitHub远程仓库每次输入账户密码问题解决(亲测可行)
在使用git push命令将本地仓库内容推送至GitHub远程仓库的每一次git都要让我们输入GitHub的用户名和密码.这着实让我们心烦.我们会有疑问,我明明设置了公钥呀!怎么还需要输入账户和密码? ...
- VUE.JS 使用axios数据请求时数据绑定时 报错 TypeError: Cannot set property 'xxxx' of undefined 的解决办法
正常情况下在data里面都有做了定义 在函数里面进行赋值 这时候你运行时会发现,数据可以请求到,但是会报错 TypeError: Cannot set property 'listgroup' of ...
- UDP反射DDoS攻击原理和防范
东南大学:UDP反射DDoS攻击原理和防范 2015-04-17 中国教育网络 李刚 丁伟 反射攻击的防范措施 上述协议安装后由于有关服务默认处于开启状态,是其被利用的一个重要因素.因此,防范可以从配 ...