Progress Monitoring
题意:给出一个序列b,b是一棵树dfs下的节点输出顺序,同一层的节点值小的优先搜索;问这棵树有几种结构形式;
思路:dp[i][j]表示i为根i+1~j是其子树的节点,然后就是看i+1~j是否可以再分为多棵树;
假设可以继续分为以i+1, k+1为根的两棵树(i+1, k在同一层) ,则必须满足b[i+1]<b[k+1]或者k==j,如下:
至于为什么是dp[i+1][k]*dp[k][j],而不是dp[i+1][k]*dp[k+1][j]或者dp[i+1][k-1]*dp[k][j],我也是有点不思其解;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll dp[510][510];//dp[i][j]表示以i为根节点的i+1~j是i的孩子节点, 注:这里的孩子并不指每个节点直接与i相连, 而是i->i+1->i+2->i+3->...->j, 是一条链;
int b[510];
ll dfs(int i, int j){
if(i==j) return 1;//一个节点可以作为一棵树;
if(dp[i][j]!=-1) return dp[i][j];//记忆化搜索;
ll ans=0;
//遍历i的所有孩子节点, 看能否以其中的节点为根节点, 产生两条链, 判断条件如下:
//k是最右的节点, 可以单独成为一颗树;
//b[k+1]>b[i+1], k~j可以单独成树;
//这里表示从k开始分叉;
for(int k=i+1; k<=j; k++){
if(k==j||b[k+1]>b[i+1]){
ans=(ans+dfs(i+1, k)*dfs(k, j)%mod)%mod;
}
}
dp[i][j]=ans;
return dp[i][j];
}
int main(){
int n;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &b[i]);
}
memset(dp, -1, sizeof(dp));
printf("%lld\n", dfs(1, n));
return 0;
}