BZOJ2744: [HEOI2012]朋友圈

题目: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=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
bool count(int x){
    int cnt=0;
    while (x){
        x-=x&(-x); cnt++;
    }
    if ((cnt&1)==0) return 1;
    return 0;
}
bool dfs(int u){
    if (ban[u]==t1) return 0;
    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]==0||dfs(mat[v])) {mat[v]=u; return 1;}
    }
    return 0;
}
int get(int x=0,int y=0){
    clr(mat,0); 
    t1++;
    int    cnt=0;
    rep(i,1,B) if (mp[x][i]||mp[y][i]) ban[i]=t1,++cnt;
    rep(i,1,B){
        ++t2;
        if (dfs(i)) cnt++;
    }
    return(B-cnt);
}
int main(){
    A=read(); B=read(); m=read();
    rep(i,1,A) a[i]=read();
    rep(i,1,B) b[i]=read();
    clr(mp,1);
    rep(i,1,m){
        int x=read(),y=read(); mp[x][y]=0;
    }
    rep(i,1,B) mp[0][i]=0;
    rep(i,1,B) if (b[i]&1){
        rep(j,1,B) if (!(b[j]&1)&&count(b[i]|b[j])) insert(i,j); 
    }
    ans=get();
    rep(i,1,A) ans=max(ans,get(i)+1);
    rep(i,1,A) if (a[i]&1)
        rep(j,1,A) if (!(a[j]&1)) ans=max(ans,get(i,j)+2);
    printf("%d
",ans);    
      return 0;
}
原文地址:https://www.cnblogs.com/ctlchild/p/5055961.html