题目描述

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

  边的描述方式很特殊,就是一次告诉你\(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. 通用权限管理系统多语言开发标准接口 - java,php 调用标准接口程序参考

    1:公司里有多个业务系统,需要进行统一重构,有PHP的.有Java的.有.NET的,甚至还有 Delphi 的. 2:公司里有多个数据库系统,有mysql的.有sqlserver的.还有oracel的 ...

  2. 15-分析Ajax请求并抓取今日头条街拍美图

    流程框架: 抓取索引页内容:利用requests请求目标站点,得到索引网页HTML代码,返回结果. 抓取详情页内容:解析返回结果,得到详情页的链接,并进一步抓取详情页的信息. 下载图片与保存数据库:将 ...

  3. JavaScript实现文字跑马灯

    其实实现文字的跑马灯和实现图片轮播的原理是一样的. 下面是我自己实现的,文字的位置可以随便更改,效果不会变,文字的内容可以通过ajax获取,同时,可以直接用Jquery改写一下,很方便. <!D ...

  4. 【学习总结】Git学习-参考廖雪峰老师教程六-分支管理

    学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...

  5. React Native之微信分享(iOS Android)

    React Native之微信分享(iOS Android) 在使用React Native开发项目的时候,基本都会使用到微信好友或者微信朋友圈分享功能吧,那么今天我就带大家实现以下RN微信好友以及朋 ...

  6. 小程序和H5互调

    小程序跳H5页面 https://blog.csdn.net/mytljp/article/details/81030687(copy) H5页面跳小程序 https://blog.csdn.net/ ...

  7. 【转】解决Maxwell发送Kafka消息数据倾斜问题

    最近用Maxwell解析MySQL的Binlog,发送到Kafka进行处理,测试的时候发现一个问题,就是Kafka的Offset严重倾斜,三个partition,其中一个的offset已经快200万了 ...

  8. WPF实现Windows资源管理器(附源码)

      今天我来写一篇关于利用WPF来实现Windows的资源管理器功能,当然只是局部实现这个功能,因为在很多时候我们需要来实现对本机资源的管理,当然我们可以使用OpenFileDialog dialog ...

  9. netstat -na 查看有大量TIME_WAIT解决办法(修改内核参数)

    # netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c      16 CLOSING     130 ESTABLISHED     298 FIN_WA ...

  10. Java 8 函数式接口

    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. 函数式接口可以被隐式转换为 lambda 表达式. Lambda 表达式和方法引用 ...