動態規劃 樹形DP

2021-10-25 20:15:29 字數 3432 閱讀 8379

樹形dp,即在樹上進行的動態規劃,由於樹固有的遞迴性質,因此樹形dp往往也遞迴進行。

某大學有 n

nn 個職員,編號為 1....

n1....n

1....n

。他們之間有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。

現在有個周年慶宴會,宴會每邀請來乙個職員都會增加一定的快樂指數 r

ir_i

ri​,但是呢,如果某個職員的直接上司來參加舞會了,那麼這個職員就無論如何也不肯來參加舞會了。

所以,請你程式設計計算,邀請哪些職員可以使快樂指數最大,求最大的快樂指數。

這道題經常被用來入門樹形dp,因為其非常明確的狀態定義。

我們令 dp[

i]

dp[i]

dp[i

] 為以 i

ii 結點為根的子樹的最優解,同時我們還需要討論,結點 i

ii 是否選取,所以可以在原陣列上加入一維,變成 dp[

i][2

]dp[i][2]

dp[i][

2] dp[

i][0

]dp[i][0]

dp[i][

0],表示 i

ii 不參加舞會的情況,i

ii 子樹的最優解。

d p[

i][1

]dp[i][1]

dp[i][

1],表示 i

ii 參加舞會的情況,i

ii 子樹的最優解。

容易想到:當 i

ii 不參加舞會時,i

ii 的子節點,可以參加舞會,也可以不參加舞會,所以這部分轉移方程為:

d p[

u][0

]=∑m

ax(d

p[v]

[0],

dp[v

][1]

)dp[u][0] = \sum max(dp[v][0], \ \ dp[v][1])

dp[u][

0]=∑

max(

dp[v

][0]

,dp[

v][1

])當 i

ii 參加舞會時,i

ii 的子節點不能參加舞會,因此只能從 dp[

v][0

]dp[v][0]

dp[v][

0]轉移過來。

d p[

u][0

]=∑d

p[v]

[0

]dp[u][0] = \sum dp[v][0]

dp[u][

0]=∑

dp[v

][0]

由於乙個結點的轉移方程需要其子節點的資料,所以轉移是在遞迴返回時進行的,搜尋部分**:

void dfs(int u, int fa)

}

樹形dp和線性dp一樣,需要考慮狀態的定義和轉移方程,只是由於樹結構上的特性,需要確定轉移順序,有些複雜的dp問題還需要多次dfs搜尋。

樹上揹包也叫有依賴的揹包問題,是揹包問題和樹形dp的結合。問題的一般形式:

有 n

nn 個物品,每個物品有其 價值 val

[i

]val[i]

val[i]

,重量 wei

[i

]wei[i]

wei[i]

,同時物品之間可能存在依賴關係,選擇物品 i

ii 則必須選擇物品 fa[

i]

fa[i]

fa[i

] ,依賴關係形成森林,求總重量不超過 w

ww 所能獲取的最大價值。

為了方便起見,我們可以對每個沒有依賴的物品新增乙個依賴 「0號物品」,即給森林的每棵樹的根節點建立乙個超級源點,這個點的價值和費用都為0,這樣避免了處理森林的麻煩。

考慮子問題,設 dp[

u][j

]dp[u][j]

dp[u][

j]為 以 u

uu 結點為根的子樹,費用不超過 j

jj 的最大價值。

假設 u

uu 有若干子節點 v1,

v2..

....

vn

v_1, \ v_2......v_n

v1​,v2

​...

...v

n​,如果把每個子樹看作一組物品,可以把這些子樹看作組內決策互斥的 n

nn 組物品,所以相當於每個結點都對其所有子節點做了一次分組揹包。

//v是費用 w是價值

void dfs(int u, int fa)

}}

樹形 dp 中的換根 dp 問題又被稱為二次掃瞄,通常不會指定根結點,並且根結點的變化會對一些值,例如子結點深度和、點權和等產生影響。

通常需要兩次 dfs,第一次 dfs 預處理諸如深度,點權和之類的資訊,在第二次 dfs 開始執行換根動態規劃。

問題:

給定乙個 個點的樹,請求出乙個結點,使得以這個結點為根時,所有結點的深度之和最大。

不妨令 u

uu 為當前結點,v

vv 為當前結點的子結點。首先需要用 s

is_i

si​ 來表示以 i

ii 為根的子樹中的結點個數,並且有 su=

∑s

vs_u = \sum s_v

su​=∑s

v​。顯然需要一次 dfs 來計算所有的 s

is_i

si​,這次的 dfs 就是預處理,我們得到了以某個結點為根時其子樹中的結點總數。

考慮狀態轉移,這裡就是體現 「換根」 的地方了。令 dp[

u]

dp[u]

dp[u

] 為以 u

uu 為根時,所有節點的深度之和。

我們需要以 u

uu 為根轉移到以 v

vv 為根。顯然在換根的過程中,以 v

vv 為根或以 u

uu 為根會導致其子樹中的結點的深度產生改變。具體表現為:

於是在第二次 dfs 遍歷整棵樹並狀態轉移 dp[

v]=d

p[u]

+n−2

∗s

vdp[v]=dp[u]+n-2*s_v

dp[v]=

dp[u

]+n−

2∗sv

​,那麼就能求出以每個結點為根時的深度和了。最後只需要遍歷一次所有結點深度和就可以求出答案。

void dfs1(int u, int fa)     //求出size陣列 

}void dfs2(int u, int fa)

}

( 動態規劃專題 ) 樹形dp

動態規劃專題 樹形dp 直接看例題 p2015 二叉蘋果樹 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3...

動態規劃(7) 樹形DP

昨天本來就能寫的,結果寫了倆個題寫了四五個小時,於是乎拖到今天了。這個題就很好寫了,不像狀態壓縮,真的是難理解 大佬部落格 f u 0 表示從以u為根節點,不選u的方案。f u 1 表示從以u為根節點,選u的方案。所以f u 0 max f si 0 f si 1 i是遍歷下一層的子節點 f u 0...

動態規劃二(樹形DP)

顧名思義,是指將dp建立在樹狀結構的基礎上。問題描述 有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?輸入格式 第一行包含乙個整數 n 接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。接...