zoukankan      html  css  js  c++  java
  • HDU 5765 Bonds

    比赛时候想了好久,不会。看了官方题解才会......

    Bond是极小割边集合,去掉一个Bond之后,只会将原图分成两个连通块。

    假设某些点构成的集合为 s(点集中的点进行状压后得到的一个十进制数),那么剩下的点构成的集合为 t=(1<<n)-1-s

    如果s是连通的,t也是连通的,那么跨越s、t集合的边的答案就+1(即跨越s、t集合的边构成一个Bond)。 

    因此,只需枚举 s 即可。

    接下来问题转变成了以下两个问题:

    1.如何判断某个点集合是否连通:状压DP预处理。

    2.如何让跨越s、t集合的边的答案+1:如果每次遍历所有的边去加答案,时间复杂度爆炸O(m*(1<<n)),因此需要换一种思路:

    我们可以计算出所有Bond有几个,然后减去(u,v)不跨越s,t的Bond个数就是(u,v)这条边的答案。

    具体看代码吧~~,再贴上官方题解:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-8;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    inline int read()
    {
        char c = getchar();  while(!isdigit(c)) c = getchar();
        int x = 0;
        while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
        return x;
    }
    
    int T,n,m,e[25],sum[(1<<20)+10],sz;
    int u[500],v[500];
    bool f[(1<<20)+10];
    
    void pre()
    {
        for(int i=0;i<n;i++) f[1<<i]=1;
        for(int i=0;i<(1<<n);i++)
        {
            if(!f[i]) continue;
            int st=0; for(int j=0;j<n;j++) if(i&(1<<j)) st=st|e[j];
            for(int j=0;j<n;j++)
            {
                if(i&(1<<j)) continue;
                if(st&(1<<j)) f[i|(1<<j)]=1;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&T); int cas=1;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            memset(e,sz=0,sizeof e); memset(f,0,sizeof f); memset(sum,0,sizeof sum);
            for(int i=0;i<m;i++)
            {
                scanf("%d%d",&u[i],&v[i]);
                e[u[i]]=e[u[i]]|(1<<v[i]), e[v[i]]=e[v[i]]|(1<<u[i]);
            }
            pre();
            for(int i=0;i<(1<<n);i++)
            {
                if(f[i]==0||f[(1<<n)-1-i]==0) continue;
                if(i>(1<<n)-1-i) break;
                sum[i]=1; sum[(1<<n)-1-i]=1; sz++;
            }
            for(int i=0;i<n;i++)
            {
                for(int j=(1<<n)-1;j>=0;j--)
                {
                    if((1<<i)&j) continue;
                    sum[j]=sum[j]+sum[(1<<i)|j];
                }
            }
            printf("Case #%d:",cas++);
            for(int i=0;i<m;i++) printf(" %d",sz-sum[(1<<u[i])|(1<<v[i])]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    【转】Pandas学习笔记(七)plot画图
    【转】Pandas学习笔记(六)合并 merge
    【转】Pandas学习笔记(五)合并 concat
    【转】Pandas学习笔记(四)处理丢失值
    【转】Pandas学习笔记(三)修改&添加值
    【转】Pandas学习笔记(二)选择数据
    17秋 SDN课程 第二次上机作业
    17秋 SDN课程 第三次上机作业
    17秋 SDN课程 第一次上机作业
    Ubuntu 14.04 安装sublime
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5723389.html
Copyright © 2011-2022 走看看