區間DP 加分二叉樹

2022-07-07 02:24:12 字數 1200 閱讀 5978

題目

設乙個n個節點的二叉樹tree的中序遍歷為(1,2,3,…,n),其中數字1,2,3,…,n為節點編號。

每個節點都有乙個分數(均為正整數),記第i個節點的分數為\(d_i\),tree及它的每個子樹都有乙個加分,任一棵子樹subtree(也包含tree本身)的加分計算方法如下:

subtree的左子樹的加分 × subtree的右子樹的加分 + subtree的根的分數

若某個子樹為空,規定其加分為1。葉子的加分就是葉節點本身的分數,不考慮它的空子樹。

試求一棵符合中序遍歷為(1,2,3,…,n)且加分最高的二叉樹tree。

要求輸出:

(1)tree的最高加分

(2)tree的前序遍歷

輸入格式

第1行:乙個整數n,為節點個數。

第2行:n個用空格隔開的整數,為每個節點的分數(0《分數<100)。

輸出格式

第1行:乙個整數,為最高加分(結果不會超過int範圍)。

第2行:n個用空格隔開的整數,為該樹的前序遍歷。如果存在多種方案,則輸出字典序最小的方案。

資料範圍

\(n<30\)

輸入樣例:

5

5 7 1 2 10

輸出樣例:
145

3 1 2 4 5

思路

這是一道非常經典的區間dp問題,奈何本蒟蒻想了半天,然後發現了這個資料範圍十分有愛。。。。

這裡使用了中序遍歷的樹的性質,也就是選中乙個節點\(k\)作為其根節點,那麼在\(k\)的左邊一定是其左子樹,右邊一定是其右子樹,並且這兩棵樹是沒有任何關係的,所以我們可以界定乙個區間f[left][right]在這個區間裡尋找乙個\(k\)使得其可以按照題意獲得最大解,然後將這個由小區間組成的集合逐漸拓展到最終的f[1][n]上來完成dp,這個做法應該是可以滿足更大的資料輸入的。

實現

#include #include using namespace std;

const int n = 50;

int value[n],f[n][n],root[n][n];

void print(int l,int r)}}

}}

cout

}

加分二叉樹(遞迴,區間DP)

演算法 區間dp,二叉樹的遍歷 狀態表示 f i j 表示中序遍歷是 w i j 的所有二叉樹的得分的最大值。狀態計算 f i j max f i k 1 f k 1 j w k 即將 f i j 表示 的二叉樹集合按根節點分類,則根節點在 k 時的最大得分即 為 f i k 1 f k 1 j w...

加分二叉樹(區間dp 樹的遍歷)

題目鏈結 思路 這題明確說明樹的中序遍歷是1 2 3 n 所以我們任取其中一段子串行,一定滿足某顆子樹的中序遍歷 故而可以考慮用區間dp 邊界就是dp i i 另外用root i j 存i到j這段的根節點。有個坑點,列舉乙個長度大於1的區間上的根的時候,根節點不可以出現在最右端,因為中序遍歷根節點不...

加分二叉樹 區間DP,記憶化搜尋)

設乙個n個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為didi,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 subtr...