#123-[樹形動態規劃]二叉蘋果樹
阿新 • • 發佈:2018-11-09
Description
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有隻有1個兒子的結點)。這棵樹共有N個結點(葉子點或者樹枝分叉點),編號為1-N,樹根編號一定是1。
我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹:
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。
給定需要保留的樹枝數量,求出最多能留住多少蘋果。
Input
第1行2個數,N和Q(1<=Q<= N,1<N<=100)N表示樹的結點數,Q表示要保留的樹枝數量。接下來N-1行描述樹枝的資訊。
每行3個整數,前兩個是它連線的結點的編號。第3個數是這根樹枝上蘋果的數量。
每根樹枝上的蘋果不超過30000個。
Output
一個數,最多能留住的蘋果的數量。
Sample Input
5 2
1 3 1
1 4 10
2 3 20
3 5 20
Sample Output
21
樹形DP的一道很經典的題.
#include <iostream> #include <vector> #define SIZE 110 using namespace std; struct edge { int to, cap; }; vector<edge> graph[SIZE]; int dp[SIZE][SIZE], m; // DP[I][J]表示第I個節點和它的子樹保留J個樹枝剩餘蘋果的最大值. int dfs(int u, int pre) // DP過程 { int i, j, k, v, w, childcount = 0; for (i = 0; i < graph[u].size(); ++i) { v = graph[u][i].to; if (v == pre) // 確保不是回到了前一個點 { continue; } w = graph[u][i].cap; childcount += dfs(v, u) + 1; for (j = min(childcount, m); j >= 1; --j) { for (k = min(j, childcount); k >= 1; --k) { dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k-1] + w); // 條件轉移方程 } } } return childcount; // 順便返回二子數 } int main(int argc, char** argv) { int n, u, v, w, i; scanf("%d%d", &n, &m); for (i = 1; i < n; ++i) { scanf("%d%d%d", &u, &v, &w); graph[u].push_back({v, w}); // 建圖 graph[v].push_back({u, w}); } dfs(1, -1); printf("%d", dp[1][m]); return 0; }