《算法竞赛进阶指南》0x53区间DP Acwing284金字塔

题目链接: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;
    }
}
原文地址:https://www.cnblogs.com/randy-lo/p/13404448.html