[Luogu2015] 二叉蘋果樹 [樹形dp]
阿新 • • 發佈:2018-11-05
感覺自己在理清碼程式碼思路上面還是有很大的不足
用樹形dp練習一下。
我就卜把這題當作二叉樹,直接套揹包啦
記f(x, c) ,表示以x為根的子樹保留c條枝最多能夠留下多少蘋果。
那麼,分類討論:
對於某個點把它保留的c條枝頭分別分給它的每個子節點
也就是說讓每個子節點用一定的價值給父親一定的貢獻。
價值怎麼分配?? 這個問題有一點點模糊,不過它實際上是一個很熟悉的模型
相當於某個子節點可以任取代價,某個代價可以得到某種價值
這是多重揹包的經典模型。
進一步考慮,化為直觀的狀態和方程。
題目要求是選一個點子樹中的點那麼這個點必須沒有被剪
於是f(x,c) = max{f(x,k)+Σf(childi,xi)+val(edge)}, Σxi=c-k-1
至於不保留這個點的情況就是f(x,0),會被父親考慮到
因為根節點一定會被選(剪不掉),所以這樣設計狀態正好合適。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define add_edge(a, b, c) nxt[++tot] = head[a], head[a] = tot, to[tot] = b, val[tot] = c
int n, q, tot;
int head[105], nxt[205], to[205], val[205], siz[105];
int f[105][105];
void dfs(int x) {
siz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
dfs(to[i]);
siz[x] += siz[to[i]];
}
for (int i = head[x]; i; i = nxt[i]) {
for (int k = siz[x] - 1; k >= 0; --k) {
for (int j = 0; j < siz[to[i]]; ++j) {
if (j >= k) continue;
f[x][k] = max(f[x][k], f[x][k-j-1] + f[to[i]][j] + val[i]);
}
}
}
}
int main() {
scanf("%d%d", &n, &q);
for (int a, b, c, i = 1; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c);
}
dfs(1);
printf("%d", f[1][q]);
return 0;
}