AcWing 479 加分二叉樹(區間dp)

2021-10-19 01:29:59 字數 2111 閱讀 5523

題目大意:

構造一顆 n

nn 個節點的二叉樹,其編號為 1,2

,3,…

,n

1,2,3,…,n

1,2,3,

…,n ,每個節點都有乙個權值 w

iw_i

wi​子樹的權值 =

== 左子樹權值 ∗

*∗ 右子樹權值 +

++ 根節點權值

若某個子樹為空,規定其權值為 1

11。葉子的加分就是葉節點本身的分數,不考慮它的空子樹。

試求一棵符合中序遍歷的節點編號為 1,2

,3,…

,n

1,2,3,…,n

1,2,3,

…,n且加分最高的二叉樹

輸出其整棵樹的最高分和此分數下字典序最小的前序遍歷

題目分析:

因為此二叉樹的中序遍歷為 1,2

,3,.

..,n

1,2,3,...,n

1,2,3,

...,

n ,當我們確定根節點編號為 k

kk 時,其左子樹的節點編號一定為 1

11 到 k−1

k-1k−

1 ,右子樹的節點編號一定為 k

kk 到 n

nn ,是互不影響的,我們考慮區間 dpdp

dp設 d p[

i][j

]dp[i][j]

dp[i][

j]表示編號為 i

ii 到 j

jj 這一段構成的子樹的最大權值

容易有轉移方程:

d p[

i][j

]=ma

x(dp

[i][

k−1]

∗dp[

k+1]

[j]+

w[k]

)dp[i][j]=max(dp[i][k-1]*dp[k+1][j]+w[k])

dp[i][

j]=m

ax(d

p[i]

[k−1

]∗dp

[k+1

][j]

+w[k

])而此題還要求方案,且字典序最小,那麼一定要有先轉移 k

kk 較小的情況,所以我們只需要邊轉移邊記錄,最後遞迴輸出方案即可

具體細節見**:

#include

#include

#include

#include

#include

#include

#include

#include

#define ll long long

#define inf 0x3f3f3f3f

#define inf 0x3f3f3f3f3f3f3f3f

//#define int ll

using

namespace std;

intread()

while

(ch>=

'0'&& ch<=

'9')

return res*flag;

}const

int maxn =

105;

const

int mod =

1e9+7;

const

double pi =

acos(-

1);const

double eps =

1e-8

;struct nodenod[maxn*maxn]

;int n,w[maxn]

,dp[maxn]

[maxn]

,root[maxn]

[maxn]

;//root[i][j]表示dp[i][j]從**轉移過來的

void

dfs(

int l,

int r)

signed

main()

}}printf

("%d\n"

,dp[1]

[n])

;dfs(1

,n);

return0;

}

Acwing 479 加分二叉樹(區間dp)

495 老師用了區間dp dp l r 是左邊界l,右邊界r的最大加分 同時還需要設乙個k表示根節點,然後dp l k 1 表示左子樹最大加分,dp k 1 r 表示有指數最大加分。然後遍歷這 一區間最大的加分就可,題目中要求輸出乙個前序的序列,那我們把每乙個最大區間也就是dp l k 1 dp k...

479 加分二叉樹

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

加分二叉樹

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