BZOJ2744: [HEOI2012]朋友圈

时间:2023-12-25 12:43:25

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2744

最大团是一个np问题。。

对于本题,做它的逆问题,建反图做最大独立集。

对于A最多取出两个点,枚举一下。

对于B,B是一个二分图。

注意用时间戳加快速度,还有就是注意一下取反的判定(||取反当然是&&

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 3005
#define inf int(1e9)
using namespace std;
struct data{int obj,pre;
}e[maxn*maxn];
int vis[maxn],head[maxn],a[maxn],b[maxn],mp[maxn][maxn],ban[maxn],mat[maxn],A,B,m,tot,t1,t2,ans;
void insert(int x,int y){
e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot;
}
int read(){
int x=,f=; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-; ch=getchar();}
while (isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
bool count(int x){
int cnt=;
while (x){
x-=x&(-x); cnt++;
}
if ((cnt&)==) return ;
return ;
}
bool dfs(int u){
if (ban[u]==t1) return ;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (ban[v]==t1||vis[v]==t2) continue;
vis[v]=t2;
if (mat[v]==||dfs(mat[v])) {mat[v]=u; return ;}
}
return ;
}
int get(int x=,int y=){
clr(mat,);
t1++;
int cnt=;
rep(i,,B) if (mp[x][i]||mp[y][i]) ban[i]=t1,++cnt;
rep(i,,B){
++t2;
if (dfs(i)) cnt++;
}
return(B-cnt);
}
int main(){
A=read(); B=read(); m=read();
rep(i,,A) a[i]=read();
rep(i,,B) b[i]=read();
clr(mp,);
rep(i,,m){
int x=read(),y=read(); mp[x][y]=;
}
rep(i,,B) mp[][i]=;
rep(i,,B) if (b[i]&){
rep(j,,B) if (!(b[j]&)&&count(b[i]|b[j])) insert(i,j);
}
ans=get();
rep(i,,A) ans=max(ans,get(i)+);
rep(i,,A) if (a[i]&)
rep(j,,A) if (!(a[j]&)) ans=max(ans,get(i,j)+);
printf("%d\n",ans);
return ;
}