• uoj#185 小星星


    dp[i][j]表示以i为根,且i在原图上对应的点为点j的方案数

    可能多个点会对应到原图中的一个点,所以要容斥处理一下

    枚举都对应到了哪些点

    dp转移方程为 dp[u][j]=π(v∈son[i])∑(k∈adj[j])dp[v][k]

    子树间方案数是乘起来啊qaq

    然后就是容斥了

    bin数组是2^i

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 30;
    
    int n,m,cnt;
    ll f[maxn][maxn],ans,res;
    int a[maxn],bin[maxn];
    
    int h[maxn],size,h1[maxn],size1;
    struct E{
        int to,next;
    }e[maxn<<5],e1[maxn<<5];
    void add(int u,int v){
        e[++size].to=v;
        e[size].next=h[u];
        h[u]=size;
    }
    void add1(int u,int v){
        e1[++size1].to=v;
        e1[size1].next=h1[u];
        h1[u]=size1;
    }
    
    void dfs(int u,int par){
        for(int i=h1[u];i!=-1;i=e1[i].next){
            int v=e1[i].to;
            if(v==par) continue;
            dfs(v,u);
        }
        
        for(int i=1;i<=cnt;i++){
            f[u][a[i]]=1;
        
            for(int j=h1[u];j!=-1;j=e1[j].next){
                int v=e1[j].to;
                ll res=0;
                if(v==par) continue;
                for(int k=h[a[i]];k!=-1;k=e[k].next){
                    res+=f[v][e[k].to];
                }
                f[u][a[i]]*=res;
                if(!res) break;
            }
        }
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}
    
    int main(){
        memset(h,-1,sizeof(h));
        memset(h1,-1,sizeof(h1));
        n=read(),m=read();
        bin[0]=1; for(int i=1;i<=n;i++) bin[i]=bin[i-1]<<1;
        int u,v;
        for(int i=1;i<=m;i++){
            u=read(),v=read();
            add(u,v),add(v,u);
        }
        for(int i=1;i<n;i++){
            u=read(),v=read();
            add1(u,v),add1(v,u);
        }
        
        for(int i=1;i<(1<<n);i++){
            cnt=0;
            memset(f,0,sizeof(f));
            for(int j=0;j<n;j++){
                if(i&(1<<j)) a[++cnt]=j+1;
            }
            dfs(1,0);
            res=0;
            for(int j=1;j<=cnt;j++) res+=f[1][a[j]];
            if((n-cnt)&1) ans-=res; else ans+=res;
        }
        printf("%lld\n",ans);
        
        return 0;
    }
  • 相关阅读:
    Django之Form、CSRF、cookie和session
    Django之路由、模板和模型系统
    简约而不简单的Django
    剑指offer(10)矩形覆盖
    剑指offer(9)变态跳台阶
    剑指offer(8)跳台阶
    剑指offer(7)斐波那契数列
    剑指offer(6)旋转数组中的最小数字
    剑指offer(5)用两个栈实现队列
    剑指offer(4)重建二叉树
  • 原文地址:https://www.cnblogs.com/tuchen/p/10412062.html
Copyright © 2020-2023  润新知