zoukankan      html  css  js  c++  java
  • BZOJ2744 HEOI2012朋友圈(二分图匹配)

      先考虑B国。容易发现a xor b mod 2=0即二进制末位相同,那么可以据此将所有人分成两部分,每一部分各自是一个完全图。然后再将a or b有奇数个1的边连上,现在需要求的就是这样一个图里的最大团。我们知道最大团=反图最大独立集,这个图的反图显然是一个二分图,那么跑二分图匹配就可以求出这个了。

      A国同样根据二进制末位分成两部分。显然不可能选择末位相同的两人。于是暴力枚举在A国选择哪些人,只留下B国与其有边的人跑匹配就可以了。

      不管复杂度。

      在一些非常弱智的地方wa了好长时间,没救。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 3010
    int n,m,k,a[N],b[N],p[N],q[N],tag[N],match[N],t,ans,tot,cnt;
    bool flag[N][N],f[N][N];
    struct data{int to,nxt;
    }edge[N*N];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    bool hungary(int k,int from)
    {
        for (int i=p[k];i;i=edge[i].nxt)
        if (tag[edge[i].to]!=from)
        {
            tag[edge[i].to]=from;
            if (!match[edge[i].to]||hungary(match[edge[i].to],from))
            {
                match[edge[i].to]=k;
                return 1;
            }
        }
        return 0;
    }
    void pre()
    {
        memset(p,0,m+1<<2);
        memset(match,0,m+1<<2);
        memset(tag,0,m+1<<2);
        tot=0;t=0;cnt=0;
    }
    void solve()
    {
        for (int j=1;j<=cnt;j++)
            for (int k=1;k<=cnt;k++)
            if (f[q[j]][q[k]]) addedge(q[j],q[k]);
        for (int j=1;j<=cnt;j++)
        if (b[q[j]]&1) tot+=hungary(q[j],q[j]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2744.in","r",stdin);
        freopen("bzoj2744.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),k=read();
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<=m;i++) b[i]=read();
        for (int i=1;i<=k;i++)
        {
            int x=read(),y=read();
            flag[x][y]=1;
        }
        for (int i=1;i<=m;i++)
            for (int j=1;j<=m;j++)
            if ((b[i]&1)&&!(b[j]&1))
            {
                int x=b[i]|b[j],y=0;
                while (x) y^=1,x-=x&-x;
                if (!y) f[i][j]=1,addedge(i,j);
            }
        for (int i=1;i<=m;i++)
        if (b[i]&1) tot+=hungary(i,i);
        ans=m-tot;
        for (int i=1;i<=n;i++)
        {
            pre();
            for (int j=1;j<=m;j++)
            if (flag[i][j]) q[++cnt]=j;
            solve();
            ans=max(ans,cnt-tot+1);
        }
        for (int x=1;x<n;x++)
            for (int y=x+1;y<=n;y++)
            if ((a[x]^a[y])&1)
            {
                pre();
                for (int j=1;j<=m;j++)
                if (flag[x][j]&&flag[y][j]) q[++cnt]=j;
                solve();
                ans=max(ans,cnt-tot+2);
            }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    windows批处理命令笔记
    linux 配置互访免密登录 sshkeygen
    jenkins 中 pipeline 管理部署服务到k8s 插件总结
    求教:Net环境导致WPF程序无法启动
    读《C程序设计语言》笔记11
    求教:.Net Framework 3.5 SP1安装失败
    设计模式
    flash基本操作二库面板和元件创建
    AUTOCAD自学教程一
    flash基本操作
  • 原文地址:https://www.cnblogs.com/Gloid/p/9609322.html
Copyright © 2011-2022 走看看