zoukankan      html  css  js  c++  java
  • bzoj2744 [HEOI2012]朋友圈——二分图匹配

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

    首先,求一个图的最大团等价于求它的补图的最大独立集,而二分图的最大独立集 = 总点数 - 最大匹配数;

    所以先把图转化成补图,也就是A国奇、偶点各自成团,B国奇、偶点相互连边而其内部无边,还有些A到B的边用邻接矩阵存了;

    可以发现A国最多只能选出两个点来,而A国选的那些点会影响B国的最大独立集;

    发现A国点很少,不妨暴力枚举!

    注意计算最大独立集时减去的数 tmp,原来写的是 tmp = 最大匹配数,其中左部点(B国奇数点)不管,右部点和A国点相连的也匹配;

    想的是右部点中和A国相连的就算匹配上了也会算在减去的部分,但这样不太对呢,而且会少算左部点中和A国相连的;

    所以直接再来一个 out 数组表示和A国点相连,把B国中左右部的 out 点都算上,然后匹配时不去匹配 out 的右部点;

    虽然感觉挺麻烦但其实也挺好写的。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    int const maxn=3005;
    int A,B,m,a[205],b[maxn],pre[maxn],ans,tmp,sid[205][maxn];
    bool vis[maxn],out[maxn];
    vector<int>vb[maxn];
    bool dfs(int x)
    {
        for(int i=0;i<vb[x].size();i++)
        {
            int u=vb[x][i];
            if(vis[u]||out[u])continue; vis[u]=1;
            if(!pre[u]||dfs(pre[u])){pre[u]=x;return 1;}
        }
        return 0;
    }
    bool ck(int x,int y)
    {
        int k=(x|y),ret=0;
        for(;k;k-=(k&-k))ret++;
        return (ret&1);
    }
    int main()
    {
        scanf("%d%d%d",&A,&B,&m);
        for(int i=1;i<=A;i++)
        {
            scanf("%d",&a[i]);
    //        if(a[i]&1)a1.push_back(i);
    //        else a2.push_back(i);
        }
        for(int i=1;i<=B;i++)
        {
            scanf("%d",&b[i]);
            for(int j=1;j<i;j++)
            {
                if(ck(b[i],b[j])||(b[i]^b[j])%2==0)continue;//补图上无边 
                vb[i].push_back(j),vb[j].push_back(i);
            }    
        }
        for(int i=1,x,y;i<=m;i++){scanf("%d%d",&x,&y); sid[x][y]=1;}
        for(int j=1;j<=B;j++)
        {
            if(b[j]%2==0)continue;//不dfs右部点 
            memset(vis,0,sizeof vis);
            if(dfs(j))ans++;
        }
        ans=B-ans;
        for(int i=1;i<=A;i++)
        {
            tmp=0;
            memset(pre,0,sizeof pre);
            memset(out,0,sizeof out);
            for(int j=1;j<=B;j++)if(!sid[i][j])out[j]=1,tmp++;//补图上有边 
            for(int j=1;j<=B;j++)
            {
                if(b[j]%2==0||out[j])continue;
    //            if(!sid[i][j]){tmp++; continue;}
                memset(vis,0,sizeof vis);
                if(dfs(j))tmp++;
            }
            tmp=B-tmp+1;
            ans=max(ans,tmp);
        }
        for(int i=1;i<=A;i++)
        {
    //        int i=a1[ii];
            if(a[i]%2==0)continue;
            for(int j=1;j<=A;j++)
            {
                if(a[j]%2==1)continue;
    //            int j=a2[jj]; 
                tmp=0;
                memset(pre,0,sizeof pre);
                memset(out,0,sizeof out);
                for(int k=1;k<=B;k++)if(!sid[i][j]||!sid[j][k])out[j]=1,tmp++;//!
                for(int k=1;k<=B;k++)
                {
                    if(b[k]%2==0||out[k])continue;//补图上有边 
                    memset(vis,0,sizeof vis);
                    if(dfs(k))tmp++;
                }
                tmp=B-tmp+2;
                ans=max(ans,tmp);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Gibbs Sampling深入理解
    MCMC算法深入理解
    蒙特卡洛法
    马尔科夫链及其平稳状态
    Dirichlet分布深入理解
    xmldecoder漏洞
    基于BindingSource的WinForm开发
    .net WinForm 的数据绑定
    C#获取网页的HTML码、下载网站图片
    4步win7下简单FTP服务器搭建(试验成功)
  • 原文地址:https://www.cnblogs.com/Zinn/p/9280895.html
Copyright © 2011-2022 走看看