NOIP 2003 加分二叉树
描述
设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
(1)tree的最高加分
(2)tree的前序遍历
格式
输入格式
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出格式
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
限制
每个测试点1s
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 using namespace std; 8 int f[1000][1000];//i 到 j 之间的最优解 ,并不是严格的 i 到 j,有可能范围更大 9 int G[1000][1000];//i 到 j 之间的根 10 int a[5000]; 11 int N; 12 inline void dfs(int l,int r){ 13 if(l>r) return ;//没这句话连样例都过不了 14 if(l==r){ 15 cout<<l<<" "; 16 return ; 17 } 18 printf("%d ",G[l][r]); 19 dfs(l,G[l][r]-1); 20 dfs(G[l][r]+1,r); 21 } 22 int main(){ 23 scanf("%d",&N); 24 for(int i=1;i<=N;i++){ 25 scanf("%d",&a[i]); 26 f[i][i]=a[i]; 27 f[i][i-1]=1;//重点,如果树成一条链,且树根在链段是会用到(无子树的情况) 28 } 29 f[N+1][N]=1; 30 for(int L=2;L<=N;L++){// L个节点之间 31 for(int i=1;i<=N-L+1;i++){//枚举起点 32 for(int k=i;k<=i+L-1;k++){//枚举根 根有可能在两端 33 int j=i+L-1;//终点 34 if(f[i][j]<f[i][k-1]*f[k+1][j]+a[k]){ 35 f[i][j]=f[i][k-1]*f[k+1][j]+a[k]; 36 G[i][j]=k; 37 } 38 } 39 } 40 } 41 cout<<f[1][N]<<endl; 42 dfs(1,N); 43 return 0; 44 }