zoukankan      html  css  js  c++  java
  • Sandy and Nuts

    题意:

    现在有一个$n$个点的树形图被拆开,现在你知道其中$m$条边,已经$q$对点的$LCA$,试求原先的树有多少种可能。

    解法:

    考虑$dp$,$f(x,S)$表示$x$的子树内的点集为$S$(不包括$x$的方案数)

    $S$被拆成$S_0 ,S_1, S_2 ... S_m$,每个集合

    这样考虑$LCA(a,b) =c$,与$<x,y> ∈ E$对$dp$的影响。

    前者相当于$a,b$分属于两个$S_i$,

    假设$x$连向的点为$y_0,y_1...$,

    后者相当于不存在$S_i$中含有两个$y_i$ 且 当$S_i$中含有一个$y_i$时,必须要将$y_i$作为$S_i - { y_i }$的父节点。

    这样,由于每一层要背包,还要状态压缩,代码十分的复杂。

    考虑类比转二叉树的方法,$f(x,S)$ 由 $f(x,S oplus S0) cdot f(p, S0 oplus p)$ 转移过来。

    这样代码会简化许多。

    枚举子集的时候应用 $ S_0 = S & (S_0-1)$ 的技巧。

    这样,总复杂度 $O(n*3^n + q*n*2^n )$。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <vector>
     5 
     6 #define N 14
     7 #define LL long long
     8 #define bit(x) (1<<(x))
     9 
    10 using namespace std;
    11 
    12 int n,m,q;
    13 int g[N];
    14 LL f[N][1<<N];
    15 vector<int> LCA[N];
    16 
    17 int get_bit(int S)
    18 {
    19     for(int i=0;i<n;i++)
    20         if(S&bit(i)) return i;
    21     return -1;
    22 }
    23 
    24 int cnt_bit(int S)
    25 {
    26     int ans=0;
    27     for(;S;S>>=1) if(S&1) ans++;
    28     return ans;
    29 }
    30 
    31 bool check(int x,int S)
    32 {
    33     for(int i=0;i<(int)LCA[x].size();i++)
    34         if((S&LCA[x][i]) != LCA[x][i]) return 0;
    35     return 1;
    36 }
    37 
    38 LL dp(int x,int S)
    39 {
    40     if(f[x][S]!=-1) return f[x][S];
    41     if(!S) return f[x][S] = 1;
    42     f[x][S]=0;
    43     int t=get_bit(S);
    44     for(int S0=S;S0;S0=(S0-1)&S)
    45         if(S0&bit(t))
    46         {
    47             bool flag=0;
    48             for(int i=0;i<(int)LCA[x].size();i++)
    49                 if((S0&LCA[x][i]) == LCA[x][i]){flag=1; break;}
    50             if(flag || cnt_bit(g[x]&S0)>1) continue;
    51             int tmp=get_bit(g[x]&S0);
    52             if(tmp!=-1)
    53             {
    54                 if(check(tmp,S0) && ( (S0|bit(x)) & g[tmp] ) == g[tmp])
    55                     f[x][S] += dp(x,S^S0)*dp(tmp,S0^bit(tmp));
    56             }
    57             else
    58             {
    59                 for(int i=0;i<n;i++)
    60                     if(S0&bit(i))
    61                     {
    62                         if(check(i,S0) && (S0&g[i]) == g[i])
    63                             f[x][S] += dp(x,S^S0)*dp(i,S0^bit(i));
    64                     }
    65             }
    66         }
    67     return f[x][S];
    68 }
    69 
    70 int main()
    71 {
    72     while(~scanf("%d%d%d",&n,&m,&q))
    73     {
    74         for(int i=0;i<n;i++)
    75         {
    76             for(int j=0;j<(1<<n);j++)
    77                 f[i][j]=-1;
    78             g[i]=0;
    79             LCA[i].clear();
    80         }
    81         for(int i=1,x,y;i<=m;i++)
    82         {
    83             scanf("%d%d",&x,&y);
    84             x--,y--;
    85             g[x]|=bit(y);
    86             g[y]|=bit(x);
    87         }
    88         for(int i=1,x,y,z;i<=q;i++)
    89         {
    90             scanf("%d%d%d",&x,&y,&z);
    91             x--,y--,z--;
    92             LCA[z].push_back(bit(x)|bit(y));
    93         }
    94         cout << dp(0,((1<<n)-1)^1) << endl;
    95     }
    96     return 0;
    97 }
    View Code
  • 相关阅读:
    "Coding Interview Guide" -- 删除无序单链表中值重复出现的节点
    "Coding Interview Guide" -- 设计一个有getMin功能的栈
    "Coding Interview Guide" -- 仅用递归函数和栈操作逆序一个栈
    "Coding Interview Guide" -- 猫狗队列
    "Coding Interview Guide" -- 阶乘
    "Coding Interview Guide" -- 不用额外变量交换两个整数的值
    IDEA问题
    JAVA
    Log4j
    MAVEN教程
  • 原文地址:https://www.cnblogs.com/lawyer/p/6591682.html
Copyright © 2011-2022 走看看