题目大意:输入一棵树的中序遍历,定义一棵子树的得分为其左子树的加分×右子树的加分+根的分数。求最大得分及先序遍历
注意:1、初始化 r[i][i]=i,便于输出
2、 初始化dp[i][i-1]=dp[i+1][i]=1。因为在区间中选取一点为root时会取到端点,即左(右)子树为空的情况,此时得分=左子树得分*1+根的分数,即给端点情况(实际这样的子树不存在)赋值为1
3、遍历顺序: 区间长度->区间起点->区间内选取根
4、区间起点的遍历n-i+1为结束,不要忘了 +1
5、区间内选取根两端点要取到
#include <iostream> #include<algorithm> #include<string.h> using namespace std; int n,a[31]; long long dp[27][27],r[27][27];//dp[i][j]表示中序遍历序列从i到j的最高得分 void print(int i,int j) { if (i>j) return ; cout<<r[i][j]<<" "; print(i,r[i][j]-1); print(r[i][j]+1,j); } int main() { int i,j,k; cin>>n; memset(dp,0,sizeof(0)); for (i=1;i<=n;i++) { cin>>a[i]; dp[i][i]=a[i]; dp[i][i-1]=1;dp[i+1][i]=1;//防止左子树(或右子树)为空的情况(虽然这个意义上的dp不存在) r[i][i]=i;//初始为叶子节点(每个都为根) } for (i=2;i<=n;i++)//区间长度 for (j=1;j<=n-i+1;j++)//区间起点,注意截止是n-i+1 for (k=j;k<=j+i-1;k++)//取区间内一点为root,注意必须两头都要取到! if (dp[j][j+i-1]<dp[j][k-1]*dp[k+1][j+i-1]+dp[k][k]) { dp[j][j+i-1]=dp[j][k-1]*dp[k+1][j+i-1]+dp[k][k]; r[j][j+i-1]=k; } cout<<dp[1][n]<<endl; print(1,n); cout<<endl; return 0; }