题意:
现在有一个$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 }