NOIP2003 提高組 加分二叉樹

題目鏈接

題目描述

設一個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個用空格隔開的整數,爲該樹的前序遍歷。

輸入輸出樣例

輸入樣例#1: 
5
5 7 1 2 10
輸出樣例#1: 
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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章