zoukankan      html  css  js  c++  java
  • BZOJ4455 小星星

    闲扯

    看到多个限制条件的计数题目,就想到容斥原理

    思路

    题目要求两个条件
    - 编号一一对应
    - 树上存在的边,在图上映射到的点上也应该存在
    考虑一个暴力的dp,设(dp_{i,j})表示i点编号对应到j点的方案数量
    转移显然是枚举每个子节点和每个子节点对应的编号
    对于每个子节点的不同方案数求和,不同子节点之间乘起来即可,复杂度(O(n^3))
    然后这样是错的,因为编号会有重复,不符合限制,考虑容斥
    (2^n)枚举子集表示哪几个编号不可以被对应,因为每有一个编号不可对应,就代表至少多出一对重复编号的点,就相当于至少重复0次-至少重复1次+至少重复2次...,最后就是一次都不重复的个数了,容斥一下就行了

    复杂度(O(2^n n^3))

    略微卡常,需要吸氧

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int u[100],v[100],fir[100],nxt[100],cnt,n,m;
    void addedge(int ui,int vi){
        ++cnt;
        u[cnt]=ui;
        v[cnt]=vi;
        nxt[cnt]=fir[ui];
        fir[ui]=cnt;
    }
    int mat[100][100],stack[100],topx;
    long long ans,dp[100][100];
    void dfs(int u,int fa){
        for(int i=fir[u];i;i=nxt[i]){
            if(v[i]==fa)
                continue;
            dfs(v[i],u);
        }
        for(int i=1;i<=topx;i++){
            dp[u][i]=1;
            for(int j=fir[u];j;j=nxt[j]){
                if(v[j]==fa)
                    continue;
                long long tmp=0;
                for(int k=1;k<=topx;k++)
                    if(mat[stack[i]][stack[k]])
                        tmp+=dp[v[j]][k];
                dp[u][i]*=tmp;
            }
        }
    }
    signed main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            mat[a][b]=mat[b][a]=1;        
        }
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        for(int S=0;S<(1<<n);S++){
            // printf("S=%lld ok
    ",S);
            memset(dp,0,sizeof(dp));
            topx=0;
            for(int i=1;i<=n;i++)
                if((1<<(i-1))&S)
                    stack[++topx]=i;
            dfs(1,0);
            long long tmp=0;
            for(int i=1;i<=topx;i++){
                tmp+=dp[1][i];
            }
            ans+=tmp*(((n-topx)%2)?-1:1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    python基础易错题
    经典案例题2
    经典案例题1
    Http和Https的区别
    爬虫过程中需要注意的问题
    [转]项目规模估计方法介绍
    [转]23种设计模式总结
    [转]分布式session的几种实现方式
    [转]Redis哨兵模式(sentinel)学习总结及部署记录(主从复制、读写分离、主从切换)
    [转]【Linux】Linux 目录结构
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10427527.html
Copyright © 2011-2022 走看看