P1040 加分二叉樹

2021-10-02 21:40:43 字數 1817 閱讀 1340

p1040 加分二叉樹

我們知道中序遍歷相同的二叉樹可能有很多種,請在滿足給定的中序遍歷的二叉樹中,找出得分最小二叉樹,輸出它的得分和前序遍歷。

得分規則:樹的得分 = 左子樹的得分 * 右子樹的得分 + 根節點的得分。

特別的,若沒有左(右)子樹,則左(右)子樹得分為1。

若為葉子節點,則得分就是葉子節點的分數。

注:題目中給出的中序遍歷是每個結點上的分數,並非結點編號,輸入序號即為結點編號。

需要輸出的前序遍歷中,要的是結點編號,而非結點分數。

搜尋所有可能的二叉樹,得到最優的結果。

搜尋問題

我們知道中序遍歷是由三部分組成,即左子樹,根結點,右子樹。當我們選擇了根節點之後,左邊的就是左子樹的中序遍歷,右邊的就是右子樹的中序遍歷。

如果我們不考慮左子樹,右子樹它們各自的內部結構,那麼對於一棵二叉樹而言,把根節點的所有可能都搜尋一邊,那就相當於把這棵樹所有可能都搜尋一邊。借用遞迴思想,我們分別對左右子樹進行相同的操作,那最終就可以真正得把所有可能的二叉樹都搜尋完畢。

記憶化搜尋問題

這裡建立dp陣列,就是把當前情況計算後的結果儲存下來,當下一次再遇到同樣情況時,可以直接獲取結果,避免重複搜尋計算。

例如對於總序列[1,2,3,4,5]中的子串行[1,2]

我們會在以3為一級根節點時,[1,2]會被作為一級左子樹計算一遍。

當我們以4作為一級根節點時,一級左子樹成為了[1,2,3],如果此時我們再以3作為二級根節點,[1,2]會被作為二級左子樹再被計算一遍。

這裡的作為二級左子樹的[1,2]和上面作為一級左子樹的[1,2],在計算結果上顯然沒有什麼不同。這種情況就是我們所說的重複情況。

前序遍歷

在上面的搜尋計算的過程中,我們可以得到在序列區間[a,b]n內讓哪個結點作為根節點為最優,我們記錄下來,最後再利用遞迴方法,把前序序列列印出來。

#include

using

namespace std;

int n;

int d[30]

,sp[30]

[30]=

;unsigned dp[30]

[30]=

;unsigned

intdfs

(int begin,

int end)

if(dp[begin]

[end]!=0

)return dp[begin]

[end]

;unsigned

int _max =

1, tmp, node;

//遍歷根節點的所有可能

for(

int i = begin;i<=end;i++)}

sp[begin]

[end]

= node;

dp[begin]

[end]

= _max;

return _max;

}void

print

(int begin,

int end)

int node = sp[begin]

[end]

; cout << node +

1<<

" ";

print

(begin,node-1)

;print

(node+

1,end);}

intmain()

P1040 加分二叉樹

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

P1040 加分二叉樹

設乙個nn個節點的二叉樹tree的中序遍歷為 1,2,3,n1,2,3,n 其中數字1,2,3,n1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第ii個節點的分數為di,treedi,tree及它的每個子樹都有乙個加分,任一棵子樹subtreesubtree 也包含treetree本...

P1040 加分二叉樹

題目 很明顯的一道區間dp題目。和acwing上的金字塔有點像。表面上感覺是樹形dp,實則不然。題中給出的1 n是中序遍歷,按照區間dp的套路 設f l r 為中序遍歷是l r的子樹的最大加分值。那麼劃分點佷顯然就是列舉一顆子樹的根節點,再加上這棵樹是一顆二叉樹就更好辦了。dp方程如下 for in...