BZOJ 2744 [HEOI2012]朋友圈 二分图 最大团
[HEOI2012]朋友圈
时空限制 1000ms / 128MB
题目描述
在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着。
一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,
所以现在就是需要你求朋友圈的最大数目。两个国家看成是 A,B 两国,现在是两个国家的描述:
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 是朋友
由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋友圈的人数吗?
输入输出格式
输入格式
第一行 t≤6 ,表示输入数据总数。
对于每组数据:
第一行三个整数 A,B,M ,分别表示 A 国人数, B 国人数, A,B 两国之间是朋友的对数
第二行 A 个数 ai ,表示 A 国第 i 个人的友善值
第三行 B 个数 bi ,表示 B 国第 i 个人的友善值
第 4 3+M 行,每行两个整数 x,y 表示 A 国的第 x 个人和 B 国第 y 个人是朋友
输出格式
输出 t 行,每行,输出一个整数,表示最大朋友圈的数目。
输入输出样例
输入样例
1
2 4 7
1 2
2 6 5 4
1 1
1 2
1 3
2 1
2 2
2 3
2 4
输出样例
5
说明
最大朋友圈包含 A 国第 1、2 人和 B 国第 1、2、3 人
第一类:|A|≤200,|B|≤200
第二类:|A|≤10,|B|≤3000
A≤200,B≤3000 ,友善为 int 类型正整数
M≤A×B≤40000
实际数据中 t=1
题解
-
观察原图:
-
A 国中的友善度奇偶性不同的点之间有边
-
B 国中所有奇数之间有边,所有偶数之间有边,奇偶不同的数之间一部分有边
-
观察朋友圈定义:
-
朋友圈是一个团
-
一般图的最大团问题是 NPC 的,然而这个图的补图很特殊
-
观察补图:
-
A 国的奇数值的点构成完全图,偶数值点构成完全图
-
B 国的奇数点和偶数点构成二分图
-
补图上朋友圈的定义:
-
朋友圈是一个独立集(最大团=补图最大独立集)
-
A 国最多取两个点,可以枚举两个点 x,y ,然后删除与 x,y 之间有边的 B 国的点
-
在 B 国剩余的点上求二分图最大独立集
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define N 3010
vector<int>e[N];
int A,B,m,T1,T2,ans,a[205],b[N],mp[205][N],tag[N],vis[N],tim[N],lik[N];
bool dfs(int u){
for(int i=0;i<e[u].size();++i){
int v=e[u][i];
if(tag[v]==T1&&vis[v]!=T2){
vis[v]=T2;
if(tim[v]!=T2||!lik[v]||dfs(v)){
lik[v]=u;
tim[v]=T2;
return 1;
}
}
}
return 0;
}
int Count(int x){
int res=0;
for(int i=x;i;i-=(i&-i)) ++res;
return res;
}
int solve(){
int res=0;
for(int i=1;i<=B;++i)
if(tag[i]==T1){
++T2;
if(dfs(i)) ++res;
} else ++res;
return B-res;
}
int main(){
//int t; scanf("%d",&t); //洛谷上需要读入t哦
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<=m;++i){
int u,v;
scanf("%d %d",&u,&v);
mp[u][v]=1;
}
for(int i=1;i<=B;++i)
if(b[i]&1)
for(int j=1;j<=B;++j)
if(!(b[j]&1))
if(!(Count(b[i]|b[j])&1))
e[i].push_back(j);
ans=max(ans,solve());
for(int i=1;i<=A;++i){
++T1;
for(int j=1;j<=B;++j)
if(mp[i][j]) tag[j]=T1;
ans=max(ans,solve()+1);
}
for(int i=1;i<=A;++i)
if(a[i]&1)
for(int j=i+1;j<=A;++j)
if(!(a[j]&1)){
++T1;
for(int k=1;k<=B;++k)
if(mp[i][k]&&mp[j][k]) tag[k]=T1;
ans=max(ans,solve()+2);
}
printf("%d",ans);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步