hdu1520——樹形DP入門及幾道簡單題
阿新 • • 發佈:2020-10-26
樹形dp
樹形DP是指在“樹”這種資料結構上進行的DP,一般來說題目會暗示你去求一個最大值或最小值(比如最小代價,最大收益之類的)。而且一般來講這種問題的規模比較大,沒辦法列舉,貪心也不能得到最優解,所以要用到動規。
而且,樹實在是太適合做動規了......因為樹本身就具有“子結構”的性質(子樹),所以在寫狀態轉移方程的時候比線性的dp更加直觀。(但是更難寫
一般來說都要用到dfs。(大概
來幾個入門題幫助理解下
hdu1520——Anniversary Party
題意大概是給定一棵樹,樹上的每個節點都有對應的權值,要求不能同時選一個節點和他的父親節點,求可以取到的最大權值。
顯然每個節點對應的狀態只有選和不選兩種,所以我們可以定義兩個狀態:
- dp[i][0]為不選當前節點時的最優解
- dp[i][1]為選擇當前節點時的最優解
同時有兩個狀態轉移方程:
- 不選擇當前節點,子節點可選可不選 : dp[i][0]+=max(dp[son][1],dp[son][0])
- 選擇當前節點,子節點不能選: dp[i][1]+=dp[son][0]
本題可以使用stl的vector建立關係樹。先找到一個根節點,然後向下dfs,在回溯時進行dp。下面是ac程式碼:
#include <bits/stdc++.h> usingnamespace std; const int N = 6005; int val[N], dp[N][2], fa[N], n; vector<int> tree[N]; void dfs(int u) { dp[u][0] = 0; dp[u][1] = val[u]; for (int i = 0; i < tree[u].size(); i++) { int son = tree[u][i]; dfs(son); dp[u][0] += max(dp[son][1], dp[son][0]); dp[u][1] += dp[son][0]; } } int main() { while (~scanf("%d", &n)) { for (int i = 1; i <= n; i++) { scanf("%d", &val[i]); tree[i].clear(); fa[i] = -1; } while (1) { int a, b; scanf("%d%d", &a, &b); if (a == 0 && b == 0) break; fa[a] = b; tree[b].push_back(a); } int t = 1; while (fa[t] != -1) t = fa[t]; dfs(t); printf("%d\n", max(dp[t][1], dp[t][0])); } return 0; }