題目描述
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有只有1個兒子的結點)
這棵樹共有n個結點(葉子點或者樹枝分叉點),編號為1-n,樹根編號一定是1。
我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。
給定需要保留的樹枝數量,求出最多能留住多少蘋果。
輸入格式:
第1行2個數,n和q(1<=q<= n,1輸出格式:
乙個數,最多能留住的蘋果的數量。
輸入樣例
5 21 3 1
1 4 10
2 3 20
3 5 20
輸出樣例
首先,題目中說了,這是顆二叉樹
有什麼用呢?
沒什麼用
其實這會讓題目變得沒有那麼複雜,乙個節點只有左右兩個兒子,存圖和遍歷的時候就多了一種方式
這是樹形揹包的經典題
然後我們開始設dp陣列
設f [i
][j]
f[i][j]
f[i][j
]表示以i
ii節點為根的子樹保留j
jj條邊時保留下來的最大蘋果數量
為什麼這樣設呢?
當然是看你的悟性。
如何看轉移
f[f當前節點為frfrr][j
]=ma
x(f[
fr][
j],f
[fr]
[j−k
−1]+
f[ca
][k]
+edg
e[i]
.dis
)f[fr][j] = max(f[fr][j], f[fr][j - k - 1] + f[ca][k] + edge[i].dis)
f[fr][
j]=m
ax(f
[fr]
[j],
f[fr
][j−
k−1]
+f[c
a][k
]+ed
ge[i
].di
s)
fr現在遍歷到的節點為caca
ca在迴圈中我們枚舉子樹的邊數k
kk總邊數為j
jj所以子樹的價值為f[c
a][k
]f[ca][k]
f[ca][
k]因為還有frfr
fr到t oto
to這條邊所以邊數要再減1
11剩下的價值就是f[f
r][j
−k−1
]f[fr][j - k - 1]
f[fr][
j−k−
1]最後加上這一條邊上的蘋果就好了
**中還會有解釋
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define a 1000010
#define b 2010
#define ll long long
using
namespace std;
struct node edge[a]
;int head[a]
, num_edge;
void
add_edge
(int from,
int to,
int dis)
int f[b]
[b], n, q, a, b, c, size[a]
;void
dfs(
int fr,
int fa)
}int
main()
dfs(1,
0); cout << f[1]
[q];
}
luogu P2015 二叉蘋果樹
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果...
Luogu P2015 二叉蘋果樹
題目鏈結 樹上零一dp 記憶化搜尋 如果是空結點 如果是葉子結點直接返回蘋果數 以上都不滿足的話,dp狀態轉移 設定dp的轉移,轉移到左右兒子結點 for int i 1 i結果31分 1.說白了,記憶化搜尋還不是掌握的特別好 2.其次狀態設計不是特別好,在儲存左右兒子時,應該該需要儲存邊的 inc...
Luogu P2015二叉蘋果樹(DP,DFS)
題目鏈結 設f i j k 表示給以i為根節點的子樹分配j條可保留的樹枝名額的時候,狀態為k時能保留的最多蘋果。k有三種情況。k 1 我只考慮子樹的左叉,不考慮子樹的右叉,此時子樹能保留的最多的蘋果。k 2 我只考慮子樹的右叉,不考慮子樹的左叉,此時子樹能保留的最多的蘋果。k 3 我既考慮子樹的左叉...