nnは(1,2,3、...、n1,2,3、...、N)として予約購入のノードのバイナリツリーを設ける場合数1,2,3、...、n1,2,3、... 、nはノードの数です。各ノードは、第二の画分と呼ばれるスコア(共に正の整数)を有するIIノードジ、treedi、木であり、そのサブツリーの各々は、任意のサブツリーsubtreesubtreeを有するプラス(それ自体も含むtreetree)次のようにボーナスが計算されます。
subtreesubtreeのルートポイント+留分の左部分木のsubtreesubtree部分×subtreesubtree右部分木の。
サブツリーが空である場合、11に加え、葉スコア余分なポイントに分割された規定は、リーフノード自体です。その空の木のに関わらず。
予約購入を決定する(...、1,2,3、...、n1,2,3、N)に準拠して、バイナリツリーtreetreeの最高点。必要な出力;
(1)treetree最高点
(2)treetree Aプレオーダートラバーサル
入力形式
行11:11の整数N(N <30)、N(N <30)、ノードの数です。
ライン22は:NN整数画分(画分<100 <100)のように、スペースで各ノードを分離しました。
出力フォーマット
11行目:11個の整数、最高点(ANS \ル4,000,000,000≤4,000,000,000)。
22行目:NN整数は、ツリーの先行順走査のために、スペースで区切られています。
サンプル入力と出力
入力#1コピー
5 5 7 1 2 10
出力#1コピー
145 3 1 2 3 4 5
アイデア:
- 左のサブツリーをトラバースするために左ルーツ、右の右のサブツリーです
- オーダートラバーサルシーケンス内のサブツリーには、まだrootとして、左の部分木は右の右部分木があり、残っています
- 最大のポイントサブバイナリツリー、バイナリツリーはまた、最大のプラスポイントです
- したがって、間隔DPとみなし、及び再帰式を描くことができる:DP [I] [J] = MAX(DP [I]、[J]、DP [i]は[M-1] * DP [M + 1] [J] + DP [M] [M]); DP [I] [j]は点の最大シーケンスを表す私は〜jは、mは数列挙ルート、I〜Jの範囲であり、バイナリツリーを形成することができます
#include<iostream>
#include<algorithm>
using namespace std;
int n,mid[32][32]={0},dp[32][32];
void first(int x,int y){ //先序遍历区间X~Y,并输出序列
if(x==y){
cout<<" "<<x;
return;
}
if(y<x)return ;
cout<<" "<<mid[x][y];
first(x,mid[x][y]-1);
first(mid[x][y]+1,y);
}
int main() {
cin>>n;
for(int i=0; i<=n; i++)
fill(dp[i],dp[i]+n+2,1);
for(int i=1; i<=n; i++)
cin>>dp[i][i],mid[i][i]=i;
for(int k=1; k<n; k++) { //枚举区间大小 ,k表示间隔大小
for(int i=1,j=i+k; j<=n; i++,j++) { //枚举区间起始和终点
for(int m=i; m<=j; m++) { //枚举树根
int t=dp[i][m-1]*dp[m+1][j]+dp[m][m]; //递推式
if(dp[i][j]<t){
dp[i][j]=t;
mid[i][j]=m; //存储树根
}
}
}
}cout<<dp[1][n]<<endl; //区间i到n的最大加分二叉树大小
cout<<mid[1][n];//输出区间1~n的树根
first(1,mid[1][n]-1); //输出区间1~n-1的所有树根
first(mid[1][n]+1,n);
return 0;
}