zoukankan      html  css  js  c++  java
  • hdu-5313 Bipartite Graph

    题意:

    给出一个全然二分图中的一些边。求这个全然二分图中最多还有多少条边。

    点数<=10000;


    题解:

    BC的pre test太坑爹了!


    显然假设想让边数最多,两边的点数越均衡越好。

    考虑到给出的图可能是不连通的,我用了并查集来维护这些点集。

    (和图上染色的算法就差了一个反ackerman函数可是省了存边深搜的麻烦)

    这样处理之后,就得到了一些二分图,之后就是将这些二分图组合起来,得到一个边数最大的二分图;

    能够用bool背包处理。可是最坏复杂度是O(n^2)的,这里用bitset来优化dp。

    能够把bitset理解为一个bool数组。而且是一个支持数组间位运算的数组。

    这些运算的复杂度是O(n/32)。dp的复杂度也就降到了O(n^2/32)    (实际上似乎更快一些?)。

    dp的详细处理见代码吧,整体来说还是十分好用的;

    加权的并查集有点绕。

    写挂了一次;


    代码:


    #include<bitset>
    #include<stack>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 11000
    using namespace std;
    int f[N];
    bool val[N];
    int hdu[N][2];
    bitset<N>bs,t;
    int find(int x)
    {
        if(f[x]==x)
            return x;
        else
        {
            int t=find(f[x]);
            val[x]=val[x]^val[f[x]];
            f[x]=t;
            return t;
        }
    }
    int main()
    {
        int c,T,n,m,i,j,k,x,y,fx,fy,cnt;
        scanf("%d",&T);
        for(c=1;c<=T;c++)
        {
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++)
                f[i]=i,val[i]=0;
            memset(hdu,0,sizeof(hdu));
            for(i=1;i<=m;i++)
            {
                scanf("%d%d",&x,&y);
                fx=find(x),fy=find(y);
                if(fx!=fy)
                    f[fy]=x,val[fy]=1;
            }
            for(i=1;i<=n;i++)
            {
                fx=find(i);
                hdu[fx][val[i]]++;
            }
            for(i=1,cnt=0;i<=n;i++)
            {
                if(hdu[i][0]||hdu[i][1])
                {
                    cnt++;
                    swap(hdu[i][0],hdu[cnt][0]);
                    swap(hdu[i][1],hdu[cnt][1]);
                }
            }
            bs=0;
            bs[0]=1;
            for(i=1;i<=cnt;i++)
            {
                t=bs;
                bs|=t<<hdu[i][0];
                bs|=t<<hdu[i][1];
                if(bs[n/2])
                break;
            }
            for(i=0;i<=n/2;i++)
            {
                if(bs[n/2+i])
                {
                    i=n/2+i;
                    break;
                }
                if(bs[n/2-i])
                {
                    i=n/2-i;
                    break;
                }
            }
            printf("%d
    ",(n-i)*i-m);
        }
        return 0;
    }
    


  • 相关阅读:
    shell加载配置文件
    Shell四种运行方式(启动方式)
    Linux下Fork与Exec使用
    ln -snf 的个人理解
    利用python3将已有的某几个pptx文件的某些slides来生成新的pptx文件的范例
    如何在centos7中安装python3
    ng-include
    ng-class细说 by破狼
    AngularJS的Filter用法详解
    理解angularjs中的$emit,$broadcast和$on by Four
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7290319.html
Copyright © 2011-2022 走看看