bzoj2744 [HEOI2012]朋友圈 ( 二分图最大团转补图最大独立集+时间戳优化+匈牙利算法)
2017-10-10 22:12
447 查看
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 ,head ,to[N*N>>2],nxt[N*N>>2],num=0,a ,b ,ans; int match ,tim ,tag ,vis ,inc=0,t=0; bool f ; 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]朋友圈
- [HEOI2012][BZOJ2744] 朋友圈|匈牙利算法|最大独立集|最大团
- BZOJ 2744 [HEOI 2012] 二分图最大独立集 解题报告
- BZOJ 2744 HEOI2012 朋友圈 二分图最大匹配
- bzoj2744 [HEOI2012]朋友圈 二分图大匹配——最大独立集
- bzoj 2744: [HEOI2012]朋友圈 (二分图最大团)
- 【BZOJ2744】【二分图】[HEOI2012]朋友圈 题解
- bzoj2744: [HEOI2012]朋友圈 二分图 最大团
- 【BZOJ 2744】 2744: [HEOI2012]朋友圈 (最大团,二分图匹配,构图)
- 【二分图】【最大匹配】【匈牙利算法】bzoj1191 [HNOI2006]超级英雄Hero
- bzoj2744【HEOI2012】朋友圈
- 二分图系列•二分图判定•匈牙利算法二分图的最大匹配•二分图最小点覆盖及最大独立集
- BZOJ 1059 矩阵游戏 (二分图最大匹配) (匈牙利算法)
- bzoj 2744: [HEOI2012]朋友圈 网络流
- 【二分图】【找最大流、最小独立集、匈牙利算法】
- POJ-2771-Guardian of Decency-求二分图最大独立集(匈牙利算法)
- HDOJ题目1068Girls and Boys(二分图最大独立集,匈牙利算法模板)
- 【BZOJ2744】【codevs2366】朋友圈,二分图最大匹配
- [BZOJ]2744: [HEOI2012]朋友圈 二分图匹配
- bzoj2744[HEOI2012]朋友圈