• HDU5765 Bonds (高维前缀和)


    HDU5765 Bonds (高维前缀和)


    题意:(n(n<=20))个点(m)条边无向图,求每条边出现在多少个(Bond)里。一个图的(cut)指,对于一个图(G)的边集的某个子集(E),如果删除(E)中的所有边,原图不连通。一个图的(Bond)指,对于一个图(G)(cut)恰好使得图不连通的边集(E),即原图去除(E)后,形成两个连通图。

    做法:首先,考虑如何求出所有的(Bond)。显然可以(2^{20})枚举出点集(A),然后如果(A)和它的补集(B),分别都是联通的,那么他们之间的所有边构成一种合法的(Bond)。这里就需要预处理点集的联通形(ok[s])。之后,考虑如何计算每条边出现在多少个(Bond)里,一种显然会(TLE)的方法是枚举所有的边和(Bond),即(O(m2^n))。考虑对于一条边(u-v)的答案,就是在所有合法的(Bond)中,(u)(v)分别属于(Bond)的两边。也就等于,所有的(Bond)的数目,去掉(u-v)都在一个集合内的数目。我们用(f[s])表示,包含点集(s)的所有合法的集合的数目,显然可以先(f[合法点集]=1),然后做超集的高维前缀和,而(f[(1<<u)|(1<<v)])就是包含(u-v)的合法集合的数目,用总的Bond数减去它就是该条边的答案。另外还有个坑点,一开始直接(bfs)这个图求(ok[s]),就(TLE)

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <queue>
    #include <cstring>
    #define IOS ios::sync_with_stdio(false)
    #define pb push_back
    #define Pii pair<int,int>
    #define Ppi pair<Pii, int>
    #define x first
    #define y second
    typedef long long ll;
    const int N = 20;
    inline void read(int &x) {
        x = 0; int f = 1; char c = getchar();
        while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
        x *= f;
    }
    using namespace std;
    int n, m, LIM, u[444], v[444], f[1 << N | 5], G[N+3];
    bool ok[1 << N | 5];
    void init_ok() {
        for(int i = 0; i < n; ++i) ok[1<<i] = 1;
        for(int s = 0; s < (1<<n); ++s) {
            if(!ok[s]) continue;
            for(int i = 0; i < n; ++i) if( !(s&(1<<i)) && (s&G[i]) ) ok[s|(1<<i)] = 1;
        }
    }
    int main() {
        int T_T, KK = 0; read(T_T);
        while(T_T--) {
            read(n), read(m);
            LIM = (1<<n)-1;
            memset(G,0,sizeof(G));memset(ok,0,sizeof(ok)); memset(f,0,sizeof(f));
            for(int i = 0; i < m; ++i) {
                read(u[i]), read(v[i]);
                G[u[i]] |= (1<<v[i]);
                G[v[i]] |= (1<<u[i]);
            }
            init_ok();
            int ans = 0;
            for(int s = 0; s <= LIM-s; ++s)  if(ok[s] && ok[LIM-s]) {
                ++ ans; f[s] = f[LIM-s] = 1;
            }
            for(int j = 0; j < n; ++j) 
                for(int i = 0; i <= LIM; ++i) 
                    if(!(i & (1 << j))) f[i] += f[i|(1<<j)];
            printf("Case #%d:",++KK);
            for(int tmp, i = 0; i < m; ++i) {
                printf(" %d", ans - f[(1<<u[i])|(1<<v[i])]);
            } putchar('
    ');
        }
    }
    
    

    高维前缀和模板

    超集

    for(int j = 0; j < n; ++j) 
        for(int i = 0; i < (1 << n); ++i) 
            if(!(i & (1 << j))) f[i] += f[i|(1<<j)];
    

    子集

    for(int j = 0; j < n; ++j)
        for(int i = 0; i< (1 << n); ++i)
            if(i & (1 << j)) f[i] += f[i^(1<<j)];
    
  • 相关阅读:
    xpath和lxml库
    pipenv和autoenv
    正则表达式
    requests库
    Photoshop学习笔记
    Firebug使用笔记
    JavaScript中的声明提升(Hoisting )
    JavaScript中的继承机制
    JavaScript中的instanceof原理详解
    JSP使用JSON传递数据,注意避免中文乱码
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/10330875.html
Copyright © 2020-2023  润新知