加分二叉樹

2022-07-21 05:27:08 字數 1562 閱讀 4037

一道入門的區間dp,當然,根據寫法不同你還可以把它歸類為樹形dp或者記憶化搜尋,其實都無所謂啦。

作為一道入門題,我們完全可以「顯然」地做出來,但是在這裡還是想和大家回顧下動態規劃以及區間動規。

q:dp特點是什麼?

a:dp把原問題視作若干個重疊的子問題的逐層遞進,每個子問題的求解過程都會構成乙個「階段」,在完成乙個階段後,才會執行下乙個階段。

q:dp要滿足無後效性,什麼叫無後效性?

a:已經求解的子問題不受後續階段的影響。

有人覺得dp很抽象,那是因為沒有一步一步來想,直接聽別人的結論,我們在這裡以這道題為例,一步一步來推導。

首先,我們要做的就是設計狀態,其實就是設計dp陣列的含義,它要滿足無後效性。

關注這個 左子樹*右子樹+根 我只要知道左子樹分數和右子樹分數和根的分數(已給出),不就可以了嗎?管他子樹長什麼樣!

所以,我們ff陣列存的就是最大分數,怎麼存呢?

我們發現:子樹是乙個或多個節點的集合。

那麼我們可不可以開乙個f[i][j]f[i][j]來表示節點i到節點j成樹的最大加分呢?可以先保留這個想法(畢竟暫時也想不到更好的了)。

如果這樣話,我們就來設計狀態轉移方程。

按照剛剛的設計來說的話,我們的答案就是f[1][n]f[1][n]了,那麼我們可以從小的子樹開始,也就是len,區間長度。有了區間長度我們就要列舉區間起點,i為區間起點,然後就可以算出區間終點j。

通過加分二叉樹的式子我們可以知道,二叉樹的分取決於誰是根,於是我們就在區間內列舉根k。

特別的,f[i][i]=a[i]f[i][i]=a[i]其中a[i]為第i個節點的分數。

因為是要求最大值,所以我們就可以設計出f[i][j]=max(f[i][k-1]*f[k+1][j]+f[k][k])f[i][j]=max(f[i][k−1]∗f[k+1][j]+f[k][k])於是乎,我們就自己設計出了乙個dp過程,因為是順著來的,所以很少有不成立的。

至於輸出前序遍歷,我們再設計乙個狀態root[i][j]root[i][j]來表示節點i到節點j成樹的最大加分所選的根節點。

所以我們按照$根->左->右$的順序遞迴輸出即可。

#include

#include

#define ll long long

using namespace std;

ll ans;

inline ll max(ll x,ll y)

int n;

ll val[200],f[40][40],root[40][40];

inline ll read()

void print(int i,int j)

printf("%d ",root[i][j]);

print(i,root[i][j]-1);

print(root[i][j]+1,j);

return;

}int main()

for(int i=n;i>=1;i--)

for(int j=i+1;j<=n;j++)}}

printf("%lld\n",f[1][n]);

print(1,n);

return 0;

}

加分二叉樹

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

加分二叉樹

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

加分二叉樹

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