顧名思義,是指將dp建立在樹狀結構的基礎上。
問題描述
有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?
輸入格式
第一行包含乙個整數 n 。
接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。
接下來一共 n-1 行,每行描述樹上的一條邊。
輸出格式
輸出乙個整數,代表選出的點的權值和的最大值。
樣例輸入
51 2 3 4 5
1 21 3
2 42 5
樣例輸出
12思路:找出選樹中的哪些節點可以得到最大的權值和。
從上往下找,每選乙個節點都要考慮其相鄰的子節點是否選中,較為麻煩,因此我們從葉子結點開始向上找。dp[i][j] 當i為底部葉子結點時,dp[i][1]表示選中i結點時的權值——k,dp[i][0]表示不選i結點時的權值——0。從下往上推,dp[i][j]當i不為葉子結點時,dp[i][1]表示選中i時,i及其子樹的最大權值;dp[i][0]表示不選i時,i及其子樹的最大權值。
因此dp的邊界即為葉子結點的狀態:
dp[i][0] = 0;
dp[i][1] = k(權值);
狀態轉移方程:
dp[i][1] = value(i)【i點權值】 + ∑dp[j][0] 【j為i的子樹根節點】
dp[i][0] = max(∑dp[j][1] ,∑dp[j][0])
當父節點擊中時,相鄰子節點必然不能選中;而當父節點未選中時,當前節點的最大權值和則為相鄰子節點擊中和未選中兩種情況中的更大值(不一定必須選中)
題目中的解即為max(dp[1][0],dp[1][1])
因為我們需要知道乙個節點的子節點有哪些,同時也要知道乙個節點的父節點有哪些(即乙個節點的臨近結點),因此我們採用字典來儲存輸入的樹。(類似儲存無向圖)
然而如何,遍歷求得dp陣列的值呢?不能像普通dp一樣直接for迴圈填充。我們使用dfs來對所有結點進行dp狀態的求解。
dfs(root) 從根節點開始對鄰接節點進行深搜,直至所有的結點都被訪問過
def
dfs_tree
(u):
#輸入結點u,輸出選擇結點u和不選擇結點u時候的最大權值
flag[u]=1
for i in
range
(len
(tree[u]))
:#遍歷u的鄰接節點個數
if flag[tree[u]
[i]]==0
:#u的i節點沒有遍歷過,則遍歷
dfs_tree(tree[u]
[i])
#對u的鄰接結點i進行dfs
#如果選擇結點u的話,其鄰接結點一定不可選
dp[u][1
]+= dp[tree[u]
[i]][0
]#沒有選擇結點u的話,其鄰接結點可選可不選,所以取這兩種情況的最大值
dp[u][0
]+=max(dp[tree[u]
[i]][1
],dp[tree[u]
[i]][0
])n =int
(input()
)#結點個數
node_list =
list
(map
(int
,input()
.split())
)#n個結點的權值
tree =
#存無向圖
for i in
range(1
,n):
root,child =
map(
int,
input()
.split())
tree.setdefault(root,
) tree.setdefault(child,
)flag =[0
for i in
range
(n+1)]
#置每個結點被訪問的狀態為0:未訪問
dp =[[
0]*2
for i in
range
(n+1)]
for i in
range(1
,n+1):
#初始化假設每個節點都是葉子結點;每個節點都被選中=自己的權值
dp[i][1
]= node_list[i-1]
dfs_tree(1)
#最大權值即為max(dp[1][0], dp[1][1])
print
(max
(dp[1]
[0],dp[1]
[1])
)
動態規劃專題(二) 樹形DP
dp 這東西真的是博大精深啊.樹形 dp 顧名思義,就是在樹上操作的 dp 一般可以用 f i 表示以編號為 i 的節點為根的子樹中的最優解。轉移的時候一般都將資訊由子節點轉移到父親節點,也就是將資訊從下往上轉移。因此,一般樹形 dp 都會採用遞迴的形式。樹形 dp 中有一種比較經典的題型 樹上揹包...
動態規劃 樹形DP
樹形dp,即在樹上進行的動態規劃,由於樹固有的遞迴性質,因此樹形dp往往也遞迴進行。某大學有 n nn 個職員,編號為 1.n1.n 1.n 他們之間有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。現在有個周年慶宴會,宴會每邀請來乙個職員都會增加一定的快樂指數 r ...
( 動態規劃專題 ) 樹形dp
動態規劃專題 樹形dp 直接看例題 p2015 二叉蘋果樹 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3...