bzoj2744 [HEOI2012]朋友圈 ( 二分图最大团转补图最大独立集+时间戳优化+匈牙利算法)
来源:互联网 发布:c 编程游戏写法 编辑:程序博客网 时间:2024/06/07 17:35
bzoj2744 [HEOI2012]朋友圈
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2744
题意:
求朋友圈的最大数目。
两个国家的描述:
1. A国:每个人都有一个友善值,当两个A国人的友善值a、b,如果a xor b mod 2=1,那么这两个人都是朋友,否则不是;
2. B国:每个人都有一个友善值,当两个B国人的友善值a、b,如果a xor b mod 2=0,或者 (a or b)化成二进制有奇数个1,那么两个人是朋友,否则不是朋友;
3. A、B两国之间的人也有可能是朋友,数据中将会给出A、B之间“朋友”的情况。
4. 在AB两国,朋友圈的定义:一个朋友圈集合S,满足S∈A∪ B ,对于所有的i,j∈ S ,i 和 j 是朋友。
求朋友圈的最大数目。
数据范围
两类数据
第一类:|A|<=200 |B| <= 200
第二类:|A| <= 10 |B| <= 3000
题解:
求朋友圈即求图中的最大团。
首先,对于A国,可以知道只有奇数和偶数可以有边,因此最多就是两个人一组。
对于B国,若求B的最大团,由题目中给出的朋友方式可知:B图的补图是二分图(按奇偶分),因为 二分图最大团 = 其补图的最大独立集,又因为 二分图最大独立集 =顶点数 - 最小顶点覆盖 并且 二分图最小顶点覆盖 = 最大匹配数 ,故可以用二分图匹配求解。
我们计算 :
1.不选国的。
2.选A国的一人(枚举A国每一个人)
3.选A国的两个人(枚举A国的每两个人)
这三种情况时,答案是B国 只包含与A国选点都是朋友的点 的图 的最大团分别加上0,1,2,取最大值即可。
每次重新建图显然不优,只需要每次时间戳++,把满足要求的点打上标记,跑匈牙利时只跑这些点即可,注意点数-匹配数时也要减去这些点。
然后一般的匈牙利每次memset掉vis数组也慢,于是又采用时间戳来优化。
(时间戳优化很棒)
代码:
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int N=3010;int A,B,m,g[N][N],head[N],to[N*N>>2],nxt[N*N>>2],num=0,a[N],b[N],ans;int match[N],tim[N],tag[N],vis[N],inc=0,t=0;bool f[N][N];bool check(int x){ int cnt=0; for(;x;x>>=1) if(x&1)cnt++; return ( (cnt%2)==1);}bool hungary(int x){ for(int i=head[x];i;i=nxt[i]) { int v=to[i]; if((tag[v]==inc)&&(vis[v]!=t)) { vis[v]=t; if(!match[v]||(tim[v]!=inc+1)||hungary(match[v])) { match[v]=x; tim[v]=inc+1; return 1; } } } return 0;}int solve(){ int ret=0; for(int i=1;i<=B;i++) if(tag[i]!=inc) ret++; for(int i=1;i<=B;i++) if(tag[i]==inc) { t++; if(hungary(i)) ret++; } return B-ret;}void build(int u,int v){ num++; to[num]=v; nxt[num]=head[u]; head[u]=num;}int main(){ scanf("%d%d%d",&A,&B,&m); for(int i=1;i<=A;i++) scanf("%d",&a[i]); for(int i=1;i<=B;i++) scanf("%d",&b[i]); for(int i=1;i<=B;i++) if(b[i]&1) for(int j=1;j<=B;j++) if((!(b[j]&1))&&!check(b[i]|b[j])) build(i,j); //建立B的补图 for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); f[x][y]=1; } inc=t=ans=0; ans=max(ans,solve()); for(int i=1;i<=A;i++) { inc++; for(int j=1;j<=B;j++) if(f[i][j]) tag[j]=inc; ans=max(ans,solve()+1); } for(int i=1;i<=A;i++) if(a[i]&1) { for(int j=1;j<=A;j++) if(!(a[j]&1)) { inc++; for(int k=1;k<=B;k++) if(f[i][k]&&f[j][k]) tag[k]=inc; ans=max(ans,solve()+2); } } printf("%d\n",ans); return 0;}
我本意是想打一道二分图来学习匈牙利,谁料完全不记得二分图性质了,在此复习:
二分图的最大匹配数=最小点覆盖数
二分图的独立数=顶点数-最小点覆盖数=顶点数-最大匹配数
二分图最小边覆盖=图中点的个数-最大匹配数=最大独立集。
二分图最大团 = 其补图的最大独立集
DAG的最小路径覆盖=原图的结点数-新图的最大匹配数(每个点拆点后作最大匹配)
然后记录下匈牙利:
bool hungary(int x){ for(int i=head[x];i;i=nxt[i]) { int v=to[i]; if(!vis[v]) { vis[v]=1; if(!match[v]||hungary(match[v])) { match[v]=x; return 1; } } } return 0;}
for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(hungary(i)) cnt++; }
- bzoj2744 [HEOI2012]朋友圈 ( 二分图最大团转补图最大独立集+时间戳优化+匈牙利算法)
- bzoj2744 [HEOI2012]朋友圈 二分图大匹配——最大独立集
- bzoj 2744: [HEOI2012]朋友圈 (二分图最大团)
- 【bzoj2744】[HEOI2012]朋友圈 二分图匹配
- 【BZOJ2744】【二分图】[HEOI2012]朋友圈 题解
- bzoj2744 二分图 最大团
- Kindergarten(求二分图最大团转化为求补图的最大独立集(再转化为匈牙利算法求最大匹配))
- 【BZOJ2744】【codevs2366】朋友圈,二分图最大匹配
- POJ3692 二分图最大团 最大独立集
- bzoj2744【HEOI2012】朋友圈
- bzoj2744[HEOI2012]朋友圈
- poj 3692 最大团(二分图匹配,最大独立集)
- bzoj 2744: [HEOI2012]朋友圈 最大团
- 最大团,最大独立集
- poj 3692(浅谈二分图最大匹配求最大独立集在解决最大团问题中的应用)
- ZOJ1137 二分图的最大独立点集 匈牙利算法
- 【二分图】【找最大流、最小独立集、匈牙利算法】
- 二分图相关拓展(抽象模型,最小顶点覆盖,边的最小覆盖,最大独立集,最大团)
- 汇编语言的寻址方式
- java鬼混笔记:lucene 8、过滤查询
- 国庆集训总结
- python机器学习基础语法入门
- 请输出1000以内能被11整除的最小的6个整数和最大的6个整数
- bzoj2744 [HEOI2012]朋友圈 ( 二分图最大团转补图最大独立集+时间戳优化+匈牙利算法)
- 计蒜客 17119 Trig Function(2017 ACM-ICPC 亚洲区(西安赛区)网络赛 F)
- 最新cygwin下使用zsh
- python中使用多进程和单进程分别拷贝大量文件效率对比
- Android NDK 编程常见错误收集
- 拓扑排序模板--hdu2647
- GeekBand笔记-《C++设计模式》第二周
- c++普通继承、虚继承、虚函数对sizeof的影响
- [HDU]1530 Maximum Clique 最大团问题[模板]