洛谷P2423 [HEOI2012]朋友圈

题目大意:

\(A,B\)两个点集,每个点有点权,在\(A\)集合中,两个点之间有边满足\(a_i\ xor\ a_j\ mod\ 2 = 1\),在\(B\)集合中,两个点之间有边满足\(b_i\ xor\ b_j\ mod\ 2=0\)或者\(b_i\ or\ b_j\)化成二进制有奇数个\(1\)

\(A,B\)集合的最大团的大小

第一类数据:\(|A|\le 200,|B|\le 200\)
第二类数据:\(|A|\le 10,|B|\le 3000\)

目前算法表示最大团问题是个\(NPC\)问题,所以我们不能直接解决

但是我们也许知道,最大团=补图最大独立集

考虑建立补图求最大独立集

对于\(A\)集合,在原图中奇偶不同的点之间有边,则在补图中奇偶相同的点之间全部有边,奇偶不同的点之间没有边,对于补图最大独立集,\(A\)图中最多选两个

对于\(B\)集合,在原图中奇偶相同的点之间有边,奇偶不同的点一些有边,则在补图中,奇偶相同的点之间没有边,我们可以以奇偶为划分标准将补图划分成二分图

建出补图后,因为\(A\)集合中点数很少,我们可以枚举\(A\)集合中选取的点,然后把与这些点构成完全图的\(B\)集合中的点标记,跑二分图最大独立集

略卡常,加时间戳优化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
namespace red{
#define eps (1e-8)
    inline int read()
    {
        int x=0;char ch,f=1;
        for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
        if(ch=='-') f=0,ch=getchar();
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    const int N=3010;
    int haku;
    int n,m,k,ret,tim,tim2;
    int T[N];
    int ap[N],bp[N];
    bool jx[N][N];
    bool jxb[N][N];
    int vis[N<<2],f[N<<2];
    int t3[N<<2];
    int py[N],num;
    int ans;
    int head[N],cnt;
    struct point
    {
        int nxt,to;
        point(){}
        point(const int &nxt,const int &to):nxt(nxt),to(to){}
    }a[N*N];
    inline void link(int x,int y)
    {
        a[++cnt]=(point){head[x],y};head[x]=cnt;
    }
    inline bool check(int x)
    {
        int sum=0;
        for(;x;x-=(x&-x)) ++sum;
        return sum&1;
    }
    inline bool find(int x)
    {
        for(int i=head[x];i;i=a[i].nxt)
        {
            int t=a[i].to;
            if(vis[t]!=tim&&T[t]==tim2)
            {
                vis[t]=tim;
                if(t3[t]!=tim||!f[t]||find(f[t]))
                {
                    f[t]=x;
                    t3[t]=tim;
                    return 1;
                }
            }
        }
        return 0;
    }
    inline int solve()
    {
        int ret=0;
        for(int i=1;i<=m;++i)
        {
            if(T[i]==tim2) ++tim,ret+=find(i);
            else ++ret;
        }
        return m-ret;
    }
    inline void main()
    {
        haku=read();
        while(haku--)
        {
            n=read(),m=read(),k=read();
            for(int i=1;i<=n;++i) ap[i]=read();
            for(int j=1;j<=m;++j) bp[j]=read();
            for(int x,y,i=1;i<=k;++i)
            {
                x=read(),y=read();
                jx[x][y]=1;
            }
            for(int i=1;i<=m;++i)
            {
                if(bp[i]&1)
                {
                    for(int j=1;j<=m;++j)
                    {
                        if(!(bp[j]&1))
                            if(!check(bp[i]|bp[j])) link(i,j);
                    }
                }
            }
            ret=max(ret,solve());
            for(int i=1;i<=n;++i)
            {
                ++tim2;
                for(int j=1;j<=m;++j)
                {
                    if(jx[i][j]) T[j]=tim2;
                }
                ret=max(ret,solve()+1);
            }
            for(int i=1;i<=n;++i)
            {
                if(ap[i]&1)
                for(int j=i+1;j<=n;++j)
                {
                    if(!(ap[j]&1))
                    {
                        ++tim2;
                        for(int k=1;k<=m;++k)
                        {
                            if(jx[i][k]&&jx[j][k]) T[k]=tim2;
                        }
                        ret=max(ret,solve()+2);
                    }
                    
                }
            }
            printf("%d\n",ret);
        }
    }
}
signed main()
{
    red::main();
return 0;
}

猜你喜欢

转载自www.cnblogs.com/knife-rose/p/12089503.html
今日推荐