洛谷 P1040 加分二叉树 & [NOIP2003提高组](区间dp,树的遍历)
传送门
解题思路
对于整个中序遍历,做一遍区间dp:
枚举区间[l...r]内的所有节点作为根节点,然后计算出得分,若比当前的值要大,同时更新dp值和root[l][r](为了输出先序遍历)。
先序是根左右,所以递归输出就好了。
AC代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int n,a[35],dp[35][35],root[35][35]; 6 void print(int l,int r){ 7 if(l>r) return; 8 if(l==r) printf("%d ",l); 9 else{ 10 printf("%d ",root[l][r]); 11 print(l,root[l][r]-1); 12 print(root[l][r]+1,r); 13 } 14 } 15 int main() 16 { 17 cin>>n; 18 for(int i=1;i<=n;i++) cin>>a[i]; 19 for(int i=1;i<=n;i++) dp[i][i]=a[i]; 20 for(int i=1;i<=n;i++){ 21 for(int j=0;j<i;j++) dp[i][j]=1; 22 } 23 for(int len=2;len<=n;len++){ 24 for(int i=1;i<=n;i++){ 25 int j=i+len-1; 26 for(int k=i;k<=j;k++){ 27 if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+a[k]){ 28 dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k]; 29 root[i][j]=k; 30 } 31 } 32 } 33 } 34 cout<<dp[1][n]<<endl; 35 print(1,n); 36 return 0; 37 }
//NOIP2003提高组 t3