題目鏈接
題目描述
設一個n個節點的二叉樹tree的中序遍歷爲(1,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個用空格隔開的整數,爲該樹的前序遍歷。
輸入輸出樣例
5 5 7 1 2 10
145 3 1 2 4 5
思路:
看到題目,以爲是二叉樹,竟然要根據中序遍歷求前序遍歷!(心想這怎麼可能)後來經過大佬指點,發現記憶化搜索就可以。
代碼:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define loop( i, a, b ) for( int i = a; i <= b; i++ )
using namespace std;
//root[i][j]爲i、j兩個節點的根節點,f數組存分數。
int n, v[10010], root[2002][2002], f[2002][2002];
int hahasearch( int l, int r ) {
if( f[l][r] > 0 ) return f[l][r];
if( l == r ) return v[l];
if( l > r ) return 1; //節點爲空時。
loop( i, l, r ) {
int p;
//得到從l到r某個點作爲根節點所得到的最多加分。
p = hahasearch( l, i - 1 ) * hahasearch( i + 1, r ) + f[i][i];
if( p > f[l][r] ) {
f[l][r] = p;
root[l][r] = i; //順帶存l、r兩個子節點的根節點。
}
}
return f[l][r];
}
//求先序遍歷
void find_tree( int l, int r ) {
if( l > r ) return; //節點爲空。
if( l == r ) { //找到葉節點。
printf( "%d ", l );
return;
}
printf( "%d ", root[l][r] ); //輸出節點。
//從根節點向左向右
find_tree( l, root[l][r] - 1 );
find_tree( root[l][r] + 1, r );
}
int main() {
scanf( "%d", &n );
loop( i, 1, n ) {
scanf( "%d", &v[i] );
f[i][i] = v[i]; //初始化f數組
}
int ans = hahasearch( 1, n );
printf( "%d\n", ans );
find_tree( 1, n );
return 0;
}