题目链接:https://www.acwing.com/problem/content/286/
给定一棵树的DFS序,求这棵树可能的形状有多少种?
由于dfs序中,每条边都访问两遍,从根节点进入只有一次,所以在有n个结点的树的DFS序的长度是2*n-1。根据区间DP,可以先构造这棵树的最右侧的子树,枚举进入的字符串,算出最右侧子树能够多少种构造方法,与左边一段的序列构造的树的数量相乘就得到了一次决策的数量,枚举右子树的进入点,进行决策的累加就得到了最终区间的决策数量。
注意:子树的dfs序的长度一定是奇数,所以在枚举左边序列组成的树的时候需要其长度是奇数。k=l代表的是左侧组成根节点,只有一个点,没有其余子树。
代码:
#include<iostream> #include<cstdio> #include<string> using namespace std; const int maxn = 310; const int mod=1e9; int f[maxn][maxn]; string s; int main(){ cin>>s; int n=s.length(); if(n%2==0)puts("0"); else{ for(int len=1;len<=n;len++) for(int l=0;l+len-1<n;l++) { int r=l+len-1; if(len==1)f[l][r]=1; if(s[l]==s[r]){ for(int k=l;k<r;k+=2){//保证子树的dfs序是奇数 if(s[k]==s[r]){ f[l][r]=(f[l][r]+(long long)f[l][k]*f[k+1][r-1])%mod; } } } } cout<<f[0][n-1]<<endl; } }