加分二叉樹


加分二叉樹

題目描述

【問題描述】 
設一個 n 個節點的二叉樹 tree 的中序遍歷爲( l,2,3,…,n ),其中數字1,2,3,…,n 爲節點編號。每個節點都有一個分數(均爲正整數),記第 j 個節點的分數爲 di , tree及它的每個子樹都有一個加分,任一棵子樹 subtree (也包含 tree 本身)的加分計算方法如下: 
subtree 
的左子樹的加分 × subtree 的右子樹的加分+ subtree 的根的分數 
若某個子樹爲主,規定其加分爲 1 ,葉子的加分就是葉節點本身的分數。不考慮它的空 
子樹。 
試求一棵符合中序遍歷爲( 1,2,3,…,n )且加分最高的二叉樹 tree 。要求輸出; 
(1 ) tree 的最高加分 
(2 ) tree 的前序遍歷

輸入格式 1794.in

第 1行:一個整數 n ( n < 30 ),爲節點個數。 
第2 行: n 個用空格隔開的整數,爲每個節點的分數(分數<100 )。

輸出格式 1794.out

第 1行:一個整數,爲最高加分(結果不會超過 4,000,000,000 )。 
第2 行: n 個用空格隔開的整數,爲該樹的前序遍歷。

輸入樣例 1794.in

5 
5 7 1 2 10

輸出樣例 1794.out

145 
3 1 2 4 5

    這題首先要讀懂題意。一開始我還把輸入的分數誤認爲中序遍歷。。。。後來發現中序遍歷是1 2 3 4 5。就是要算加分最多的樹的分數和先序遍歷。

    代碼無比友善,一看就懂,但是要想出來,好吧,我還是想不出來。(⊙o⊙)…

    這題的狀態的確定是非常重要的,我覺得這個狀態也挺特別。f[i][j]代表,從第i個結點到第j個結點的數的最大加分。

    枚舉一個i和j,i從大到小,j從小到大。我和wyy還討論過爲啥i要從大到小,反過來變成i從小到大,j從大到小不行嗎。後來她解釋說,如果這樣的話,範圍就變成1~n,問題就變大了。

    然後枚舉一個根節點k

f[i][k-1]*f[k+1][j]+f[k][k]>f[i][j]那就賦值,用一個數組b[i][j]記錄下從i到j得出最大值的根節點,方便後面的輸出。

    

    要做一點預處理,首先,把所有的f[i][j]都賦爲1,如果沒有左子樹時,那就只用右子樹加根節點,如果f[i][j]是0,一乘,得出來的結果就是0了,而不是我們所要的右子樹加根節點。其次,把f[i][i]=a[i],b[i][i]=i這個我就不用解釋了。

    一開始的時候,我陷入了死循環,因爲我忘記給b初始化了。然後後來一交,竟然是0分,發現我輸出的格式是不對的,本來兩個結點之間有一個空格,我打了兩個。。。腦殘無比。

#include
#include
using namespace std;
int n,f[35][35],b[35][35],a[35];
void DP()
{
	for(int i=n;i>=1;i--)
	{
		for(int j=i+1;j<=n;j++)
		{
			for(int k=i;k<=j;k++)
			{	
				if((f[i][k-1]*f[k+1][j]+f[k][k])>f[i][j])
				{
					f[i][j]=f[i][k-1]*f[k+1][j]+f[k][k];
					b[i][j]=k;
				}
			}
		}
	}
}
void first(int l,int r)
{
	if(l<=r)
	{
		cout<>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=n;j++) f[i][j]=1;
	}
	for(int i=1;i<=n;i++) 
	{
		f[i][i]=a[i];
		b[i][i]=i;
	}
	DP();
	cout<
發佈了39 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章