BZOJ 2744 朋友圈 (最大团)
来源:互联网 发布:初音未来眼药水 淘宝 编辑:程序博客网 时间:2024/06/05 19:14
2744: [HEOI2012]朋友圈
Time Limit: 30 Sec Memory Limit: 128 MB
Description
在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着。一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,所以现在就是需要你求朋友圈的最大数目。
两个国家看成是AB两国,现在是两个国家的描述:
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之间“朋友”的情况。
- 在AB两国,朋友圈的定义:一个朋友圈集合S,满足
S∈A∪ B ,对于所有的i,j∈ S ,i 和 j 是朋友
由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋 友圈的人数吗?
Input
第一行t<=6,表示输入数据总数。
接下来t个数据:
第一行输入三个整数A,B,M,表示A国人数、B国人数、AB两国之间是朋友的对数;第二行A个数ai,表示A国第i个人的友善值;第三行B个数bi,表示B国第j个人的友善值;
第4——3+M行,每行两个整数(i,j),表示第i个A国人和第j个B国人是朋友。
Output
输出t行,每行,输出一个整数,表示最大朋友圈的数目。
Sample Input
2 4 7
1 2
2 6 5 4
1 1
1 2
1 3
2 1
2 2
2 3
2 4
Sample Output
5
【样例说明】
最大朋友圈包含A国第1、2人和B国第1、2、3人。
HINT
【数据范围】
两类数据
第一类:|A|<=200 |B| <= 200
第二类:|A| <= 10 |B| <= 3000
思路:
摘自 < barrykanry >
当时做的时候,一看要求就是要求一个最大团,一般的图求最大团是指数级的肯定不可能 ,那么最大团可以接受的算法就是二分图的最大团了,nm的。
考虑二分图的最大团的条件,即两个集合,每个集合的元素之间互相两两有边,然后两个集合互相有边,跑最大团但是把这两个集合当成A和B来做的话显然不太合适,因为首先就没有满足A集合或者B集合两两有边的条件。
但是这道题的建边方式不一般,肯定有什么门道。
观察发现A中元素的朋友的条件是友善值一奇一偶,灵光一现A最多两个人,那我们就枚举哪两个人,然后把他们相交的部分在B集合里面选出来然后搞一个最大团,但是这个最大团的复杂度严格来说和直接求是一致的,那还是要往二分图上想 。
考虑B里面是朋友的方式 ,然后想到只要都是奇数,或者都是偶数,互相之间肯定是有边的,那么就完全转化成二分图的模型了,用补图的最大点独立集就好。
最好不要每次memset,搞一个时间戳什么的比较好。
注意这道题的输入里面有重边,所以判断每次B里面选了几个的时候需要略略注意一下。
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <vector>#define N 3010using namespace std;struct Edge{ int to, nxt;}ed[N * N];vector <int> va[N];int A, B, M, idc=0, cc=0, tot=0, timex=0;int head[N], mrk2[N], mrk1[N];int a[N], b[N], lnk[N], flag[N];void adde(int u, int v){ ed[++idc].to = v; ed[idc].nxt = head[u]; head[u] = idc;}int find(int u){ for(int i = head[u]; i; i = ed[i].nxt){ int v = ed[i].to; if(mrk2[v]==timex && flag[v]!=cc){ flag[v] = cc; if(!lnk[v] || find( lnk[v] )){ lnk[u] = v, lnk[v] = u; return 1; } } } return 0;}bool check(int i, int j){//或起来有奇数个1 int x = b[i] | b[j], cnt = 0; while( x ){ if(x & 1) cnt++; x >>= 1; } if(cnt & 1) return 1; else return 0;}void build(){//建补图 for(int i=1; i<=B; i++) if(b[i] & 1) for(int j=1; j<=B; j++) if( !(b[j] & 1) && !check(i, j)) adde(i, j); }int work(){ int ans = 0; cc = 0; memset(lnk, 0, sizeof(lnk)); for(int i=1; i<=B; i++) if( ( b[i] & 1 ) && mrk2[i] == timex ){ cc++;//时间戳 if( !lnk[i] ) ans += find( i ); } return tot - ans;}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]); while ( M-- ){ int u, v; scanf("%d%d", &u, &v); va[u].push_back( v ); } build(); int ans = 0; timex++;//是否可选 for(int i=1; i<=B; i++) mrk2[i] = timex; tot = B; ans = max(ans, work());//不选A for(int i=1; i<=1; i++){//选一个A tot = 0, timex++; for(int j=0; j<va[i].size(); j++) mrk2[va[i][j]] = timex; for(int j=1; j<=B; j++) if(mrk2[j] == timex) tot++;//可能有重边 tot为总点数 ans = max(ans, work() + 1); } for(int i=1; i<A; i++){//选两个A for(int j=i+1; j<=A; j++){ if ( (a[i] ^ a[j]) & 1 ){ tot = 0, timex++; for(int k=0; k<va[i].size(); k++) mrk1[va[i][k]] = timex; for(int k=0; k<va[j].size(); k++) if(mrk1[va[j][k]] == timex) mrk2[va[j][k]] = timex, tot++; ans = max(ans, work() + 2); } } } printf("%d\n", ans); return 0;}
- BZOJ 2744 朋友圈 (最大团)
- bzoj 2744: [HEOI2012]朋友圈 (二分图最大团)
- bzoj 2744: [HEOI2012]朋友圈 最大团
- bzoj 4206: 最大团 (DP+几何)
- 组队(最大团)
- 最大团(dfs)
- 【最大团】【bzoj 3632】: 外太空旅行
- BZOJ 3632 外太空旅行 最大团
- bzoj 2445 最大团 CRT 组合数取模
- bzoj2744 [HEOI2012]朋友圈 ( 二分图最大团转补图最大独立集+时间戳优化+匈牙利算法)
- BZOJ 2744: [HEOI2012]朋友圈
- BZOJ 2744: [HEOI2012]朋友圈
- BZOJ 2744: [HEOI2012]朋友圈
- BZOJ 2744 浅谈异或二进制分析及二分图最大团
- bzoj 2445 最大团(阶乘取模+中国剩余定理CRT)
- poj(3962)最大团
- POJ3692:Kindergarten(最大团)
- 最大团算法(codeforces839E)
- 87. Scramble String
- Equation UVA
- NOIP模拟(10.30)T3 星星
- 当使用makemigrations时报错No changes detected
- 点亮细胞111-120
- BZOJ 2744 朋友圈 (最大团)
- 10.30
- Python学习笔记之数据类型与变量 字符串 list tuple
- Java面向过程与面向对象的思维模式
- C++面试之堆栈
- 点亮细胞121-130
- IntelliJ IDEA 激活 [转]
- anaconda环境变量+修改jupyter默认路径
- TensorFlow优化模型之正则化