题目描述

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

  边的描述方式很特殊,就是一次告诉你\(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_JUDGEchar 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;
}

转载于:https://www.cnblogs.com/ywwyww/p/8573863.html

【XSY2774】学习 带花树相关推荐

  1. 【学习小记】一般图最大匹配——带花树算法

    Text 一般图的最大匹配仍然是基于寻找增广路的 增广路的定义是这样的一条路径,它不经过重复的点,并且路径两端均没有匹配,且整条路径是非匹配边-匹配边-非匹配边这样交错的. 类比二分图最大匹配的增广路 ...

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

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

  3. luogu P4258 [WC2016]挑战NPC(一般图的最大匹配,带花树,建图、拆点技巧)

    整理的算法模板合集: ACM模板 luogu P4258 [WC2016]挑战NPC 如果是一堆球一堆筐,每一个筐里只能放一个球,求最大能放多少个球, 那么就是一个二分图的最大匹配问题,非常简单,我们 ...

  4. 模板 - 一般图最大匹配(带花树)

    整理的算法模板合集: ACM模板 目录 题目描述 给出一张 n 个点 m 条边的无向图,求该图的最大匹配. 总结一下带花树算法的流程 1.每次找一个未匹配的点出来增广 2.在增广过程中,如果相邻点是白 ...

  5. luogu P6113 【模板】一般图最大匹配(带花树)

    整理的算法模板合集: ACM模板 总结一下带花树算法的流程 1.每次找一个未匹配的点出来增广 2.在增广过程中,如果相邻点是白点,或者是同一朵花中的节点,则直接跳过这个点 3.如果相邻点是一个未被匹配 ...

  6. WC前的颓废——带花树

    QAQ现在很不想写题解博客那就来写个算法吧QAQ... 带花树 题目 来看个题... UOJ79. 某机房里有\(n\)个OIer,其中有\(n\)个男生,\(0\)个女生.现在他们要两两配对. 有\ ...

  7. 【BZOJ4405】【WC2016】挑战NPC(带花树)

    [BZOJ4405][WC2016]挑战NPC(带花树) 题面 BZOJ 洛谷 Uoj Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个 ...

  8. URAL - 1099 Work Scheduling(一般图最大匹配-带花树模板)

    题目链接:点击查看 题目大意:给出n个警卫,接下来给出数个关系,表示两个警卫可以互相配合,现在规定只有可以互相配合的警卫才能留下来继续工作,问最多能有多少个警卫留下来工作,输出匹配方案 题目分析:一般 ...

  9. 一般图最大匹配——带花树

    所谓花,就是如下图所示的一个奇环: 本文中粗边代表现在的匹配边,细边代表该点的前驱(后文会讲解前驱是什么,现在只需要知道每个点和它的前驱在原图中一定是有边的). 如图所示,一朵包含\(2k+1\)个点 ...

  10. 图论--一般带花树匹配

    带花树就是说一个非二分图,图中带有奇环的图,我们不能在奇环中找增广路,因为会陷入死循环,我们可以将带花树的花(奇环)部分缩成点处理,剩下的图就是一个无奇环的图.我们再找增广路,而奇环中的的点我们可以随 ...

最新文章

  1. Cocos事件监听(JS)
  2. 201671010140. 2016-2017-2 《Java程序设计》java学习第一周
  3. 数据查找matlab,MATLAB:使用矢量化查找已排序数据的统计信息
  4. lisp 绘制立体感的五角星_[原创]圆内加五角星lsp代码,详细有注解
  5. 发动机压缩比怎么计算公式_怎么判断发动机有积碳,发动机积碳多的症状有哪些...
  6. php http agent,PHP通过http头user-agent判断是否为手机浏览器
  7. Mybatis-no getter for property named 'col_name' in 'class com.xxx.onebean'
  8. Nodejs 文件 与 路径 相关用法实例解析
  9. webpack配置babel-loader
  10. 德清租房软件测试,门头沟实习生出租房
  11. python学习之编写学员管理系统
  12. bixby服务器没响应,猫盘开启ssh教程(原版系统,听闻一键x3p已经不能用了!)...
  13. 北京大学生物信息学(9)第二代基因组测序技术
  14. APP推广干货:10条线上渠道引爆APP流量
  15. 非常实用,华为、新华三、锐捷交换机的配置命令分享
  16. 数字逻辑设计基础(何建新)第三章
  17. 斗地主十句口诀技巧全解
  18. 史上最详细Mysql免安装版教程
  19. 2023NPDP产品经理认证如何考取?
  20. 如何登录锐捷设备(网关篇)

热门文章

  1. Android注解编程的第一步---模仿ButterKnife的ViewBinder机制
  2. DevExpress换肤功能使用方法
  3. Web前端学习笔记(三)——input标签的属性
  4. Win10使用tensorflow出现ImportError: DLL load failed: 动态链接库(DLL)初始化例程失败
  5. 任务方案思考:句子相似度和匹配
  6. 哪个员工上班健身,定性考勤造假;哪个员工反映问题,考虑把他清退!华为HR实名内曝...
  7. “不可不学是编程,不可不用是git” | github篇
  8. numpy-np.random.permutation
  9. 深度学习2.0-11.tensorflow的高阶操作之高阶op
  10. 牛客——数据库实战(31~61)