NOIP 2003 加分二叉樹

2021-08-07 09:50:42 字數 1787 閱讀 6021

問題描述

設乙個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的前序遍歷

輸入格式

第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

主要考察點應該是二叉樹的遍歷。把遍歷的特性弄清楚之後就是一道比較水的區間dp。

1.有關定義:

① 前序遍歷:先訪問根節點,再訪問左子樹,最後訪問右子樹。

② 中序遍歷:先訪問左子樹,再訪問根節點,最後訪問右子樹。

③ 後序遍歷:先訪問左子樹,再訪問右子樹,最後訪問根節點。

2.一些性質:

① 前序遍歷中,最先訪問的是整棵樹的根節點。

② 後序遍歷中,最後訪問的是整棵樹的根節點。

③ 中序遍歷中,根的整棵左子樹總在根之前被訪問,根的整棵右子樹總在根之後被訪問。

④ 已知前序遍歷和後序遍歷,不能得出整棵樹的結構;只要知道中序遍歷和其他兩種遍歷之一,就能得出唯一的整棵樹的結構。

本題主要利用性質③。由性質③可知,選定乙個節點作為根之後,左子樹一定在它的左邊,右子樹一定在它的右邊,於是就成了一道裸的區間dp。

dp過程中記錄下將區間[l,r]作為子樹時得分最高的根,根據dp的最優子結構性質,通過遞迴的方式就能得出前序遍歷。

//**採用的是記憶化搜尋的方式

#include

#define ll long long

int n,sc[50],rt[50][50];

ll f[50][50];

void dp(int l,int r)

if(l>r)//空子樹加分為1

int i;

for(i=l;i<=r;i++)//依次討論根節點

}}void dfs(int p,int l,int r)//遞迴求後序遍歷

printf("%d ",p);

dfs(rt[l][p-1],l,p-1);

dfs(rt[p+1][r],p+1,r);

}int main()

NOIP 2003 加分二叉樹

評測傳送 這個題可以記憶化搜尋做的。注意邊界條件。對於先序遍歷,遞迴就可以了 在dfs的時候用乙個陣列記錄根節點就可以了 include include include include include include define ll long long using namespace std i...

NOIP2003 加分二叉樹題解

設乙個n 個節點的二叉樹t 的中序遍歷為 1,2,3,n 其中數字 1,2,3,n 為節點編號。每個節點都有乙個分數 均為正整數 記第j 個節點的分數為dj。二叉樹t 及它的每個子樹都有 乙個加分,任意一棵子樹s 包括t 本身 的加分等於s 的左子樹的加分 s 的右子樹的加分 s的根的分數。若某棵子...

noip 2003 加分二叉樹(DP)

題目鏈結 思路 用乙個二維陣列dp i,j 表示中序遍歷中從 i 到 j 的區間組成的子樹的集合,dp i,j 的值表示這些子樹中得分的最大值,轉移方程很簡單,dp i,j max dp i,j dp i,k 1 dp k 1,r 需要遍歷 i 到 j 的每乙個點,判斷哪乙個是根節點,然後根據根節點...