題目傳送門
description
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有只有1個兒子的結點)
這棵樹共有n個結點(葉子點或者樹枝分叉點),編號為1-n,樹根編號一定是1。
我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹
2
5 \ /34
\ /1
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。
給定需要保留的樹枝數量,求出最多能留住多少蘋果。
input
第1行2個數,n和q(1<=q<= n,1
output
乙個數,最多能留住的蘋果的數量。
sample input
5 21 3 1
1 4 10
2 3 20
3 5 20
我們觀察到題目資料量不大,所以有兩種選擇:鄰接矩陣和鄰接表。因為鄰接矩陣的**簡單,思路清晰,所以建議能寫鄰接矩陣的時候就不要寫鄰接表了。我們設ma[x][y]為邊的值,因為樹是雙向的,所以要再記錄ma[y][x]。
設tree[v,1]為節點v的左子樹,tree[v,2]為節點v的右子樹,然後我們再遞迴建樹(因為樹是遞迴定義的,所以很多時候建樹都要考慮遞迴)。
建樹的問題解決的了,我們就要列狀態轉移方程了。根據求什麼設什麼的原則,我們定義f[i][j]表示以i為節點的根保留k條邊的最大值,那麼f[v][k]=max(f[v][k],(f[tree[v][1]][i]+f[tree[v][2]][k-i-1]+num[v])),我們列舉i就可以了。正如我開頭提到的。因為樹是遞迴定義的所以我們可以用記憶化搜尋的形式(dfs)來具體實現。而樹本身嚴格分層,而且沒有環。所以是不會重複的。
f[1][q+1]就是答案。因為題目中給的是邊的權值,而我們在處理時將每條邊的權值全賦給其所連的父節點和子節點中的子節點(將關於邊的問題轉化為關於點的問題),所以最後是q+1,表示點的數目
#include
#include
using
namespace std;
int n,q,b[
105]
,a[105][
105]
,f[105][
105]
,tree[
105]
[105];
void
build
(int x)
//建圖
}void
dfs(
int x,
int k)
//搜尋}}
intmain()
build(1
);//建dfs(1
,q+1);
//搜 cout<[q+1];
//輸出
}
樹形dp入門 P2015 二叉蘋果樹
題目描述 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1現在這顆樹枝條太多了,需要剪枝。但是一些樹...
洛谷 P2015 二叉蘋果樹 樹形dp
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋...
洛谷P2015 二叉蘋果樹(樹形dp)
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋...