所謂樹規,簡單來說就是在樹這個結構上做普通dp.它所考慮的東西只比普通dp多兩點:建圖和遍歷.
我個人比較喜歡用鄰接表存圖,然後鏈式前向星和鄰接矩陣等憑個人愛好選擇;而遍歷往往只有兩種:根到葉子節點和葉子到根節點,一般後者使用比較廣泛,而實現用遞迴即可.
接下來思考這道題
(由於只是dp乙個基礎題,所以還是只給傳送門吧):
這道題很容易想到每個人只有兩種狀態:去和不去.
所以我們用f[i
][1]
f[i][1
]和f[i]
[0]f[
i][0
]分別表示第i
i個人去和不去時的ta與ta的所有下屬的快樂度總值,最後後答案即:
a ns
=max
(f[r
oot]
[0],
f[ro
ot][
1])(
root
為根節點
)an
s=ma
x(f[
root
][0]
,f[r
oot]
[1])
(roo
t為根節
點)進行進一步分析,我們發現:
若節點u選擇去,那麼它的子節點v只能不去,然後有dp轉移方程:
f [u
][0]
=f[u
][0]
+f[v
][0]
f[u][0
]=f[
u][0
]+f[
v][0
];若節點u選擇不去,那它的子節點v可去可不去,然後有dp轉移方程:
f [u
][1]
=f[u
][0]
+max
(f[v
][0]
,f[v
][1]
)f[
u][1
]=f[
u][0
]+ma
x(f[
v][0
],f[
v][1
]);解決完dp後我們再來解決樹的問題:先用鄰接錶連邊(由根->葉),
統計每個點的入度,再掃瞄一次,若掃到乙個節點入度為0,那這個節點就為根節點,最後由根開始dfs一遍更新答案即可.
#include
#define n 6003
using
namespace std;
int n,tot,ans,root;
int a[n]
,f[n][2
],fi[
2*n]
,nxt[
2*n]
,to[
2*n]
;bool rd[n]
;inline
void
lian
(int u,
int v)
//鄰接表
inline
void
dfs(
int u)
return;}
intmain()
for(
int i=
1;i<=n;i++
)//尋根
}dfs
(root)
;//從根開始
ans=
max(f[root][0
],f[root][1
]);printf
("%d\n"
,ans)
;return0;
}
以上為個人見解,望本篇部落格對各位有所幫助. DP 樹形 DP 樹的中心
做法 a 大致想法是進行兩遍dfs,找到每個節點的向下的最長路徑 di 和向上的最長路徑 ui 然後列舉每乙個點,再找到min max di ui b 補充細節 1 根據樹的直徑求法,向下求的時候會有乙個最大值和次大值,例如節點 i 的 d1i d2i,當更新 i 的某個子節點 j 的 uj 時候,...
DP練習 奶牛的鍛鍊
奶牛bessie有n分鐘時間跑步,每分鐘她可以跑步或者休息。若她在第i分鐘跑步,可以跑出d i公尺,同時疲倦程度增加1 初始為0 若她在第i分鐘休息,則疲倦程度減少1。無論何時,疲倦程度都不能超過m。另外,一旦她開始休息,只有當疲憊程度減為0時才能重新開始跑步。在第n分鐘後,她的疲倦程度必須為0。第...
樹形dp 樹的重心
1.只需要求出最大子樹中節點數最小的數目即可 題意 有乙個國王要把他的領土分給兩個兒子,國王的領土是一棵樹,n個結點,n 1條邊把這些結點連起來,現在大小兒子要選擇乙個點作為他的首都,那麼除首都分別是這兩個兒子之外,其他的城市 結點 根據離誰近就歸誰所有,如果一樣遠的話就歸大兒子所有,現在假設兩個人...