zoukankan      html  css  js  c++  java
  • BZOJ 2744: [HEOI2012]朋友圈

    传送门

    解题思路

    直接跑最大团洛谷上能得70分,惊了。说说正解,首先A国的必须xor后mod2余1,就相当于两个人必须是1奇1偶,所以A国的人只能选0,1,2个,我们可以暴力枚举选谁。继续考虑B国,现在的问题实际上就简化为了在B国中选出一个最大团,这个团也必须和A国所选出的人是朋友,又因为最大团=总点数-补图的最大匹配,补图就是将原来连着的边断了,原来没连的边连上,而进一步可以发现其实B国的补图是一个二分图,左部点是%2余1的,右部点是%2余0的,如果它们或起来有偶数个1就可以连边,然后就是二分图中求一个最大匹配,我用的匈牙利卡了过去。。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    
    using namespace std;
    const int MAXN = 3205;
    const int MAXM = 1500*1500+5;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    
    int T,A,B,M,head[MAXM],cnt,ans;
    int to[MAXM],nxt[MAXM],now;
    int a[MAXN],b[MAXN],e[MAXN][MAXN];
    int num,t,vis[MAXN],flag[MAXN],match[MAXN];
    
    inline void add(int bg,int ed){
        to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
    }
    
    inline bool dfs(int x){
        for(register int i=head[x];i;i=nxt[i]){
            int u=to[i];
            if(vis[u]!=num && flag[u]==t){
                vis[u]=num;
                if(!match[u] || dfs(match[u])){
                    match[u]=x;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main(){
    //  T=rd(); 
        A=rd();B=rd();M=rd();
        for(register int i=1;i<=A;i++) a[i]=rd();
        for(register int i=1;i<=B;i++) b[i]=rd();
        for(register int i=1;i<=B;i++)if((b[i]&1))
            for(register int j=1;j<=B;j++) 
                if(!(b[j]&1) && !((__builtin_popcount((b[i]|b[j])))&1)) add(i,j);
        for(register int i=1;i<=M;i++) {
            int x=rd(),y=rd();
            e[x][y+A]=e[y+A][x]=1;
        }
        for(register int i=1;i<=B;i++)if((b[i]&1)){
            num++;
            if(dfs(i)) ans++;
        }ans=B-ans;
        for(register int i=1;i<=A;i++){
            t++;int sum=0;now=0;
            memset(match,0,sizeof(match));
            for(register int j=1;j<=B;j++)
                if(e[i][j+A]) flag[j]=t,now++; 
            for(register int j=1;j<=B;j++)
                if(flag[j]==t && (b[j]&1)) {
                    num++;
                    if(dfs(j)) sum++; 
                }
            ans=max(ans,now-sum+1);
        }
        for(register int i=1;i<=A;i++)
            for(register int j=i+1;j<=A;j++)if((a[i]^a[j])&1){
                memset(match,0,sizeof(match));
                t++;int sum=0;now=0;
                for(register int k=1;k<=B;k++)
                    if(e[i][k+A] && e[j][k+A]) flag[k]=t,now++;
                for(register int k=1;k<=B;k++)
                    if(flag[k]==t && (b[k]&1)) {
                        num++;
                        if(dfs(k)) sum++;
                    }
                ans=max(ans,now-sum+2);
            }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    C#解析PDF
    Ora-03113Ora-03114与Oracle In 拼接字符串的问题
    [Linux] nohup/setsid/& 让进程在后台可靠运行
    [Python] json 报错'xxx is not JSON serializable'的处理方法
    [Linux] 虚拟环境的配置和使用 virtualenv
    [Python] 跳过前几行快速读取文件内容:islice
    对pandas的dataframe绘图并保存
    matplotlib 数据可视化
    awk结合正则匹配
    Pandas库常用函数和操作
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676855.html
Copyright © 2011-2022 走看看