题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
/
3 4
/
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
输入格式
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
输出格式
一个数,最多能留住的苹果的数量。
输入输出样例
输入 #1
5 2 1 3 1 1 4 10 2 3 20 3 5 20
输出 #1
View Code
21
题解:
树形背包模板题,考虑到每次删减最小的边有后效性,无法得出正解可以考虑背包
f[u][i]表示以u为根节点的拥有i条边的子树拥有的最大苹果数量。
显然转移方程可以写成:
f[u][i] = max(f[u][i], f[u][i - j + 1] + f[v][j] + w[i])
接着直接套树形背包的模板即可。
CODE
1 #include <bits/stdc++.h> 2 #define dbug(x) cout << #x << "=" << x << endl 3 #define eps 1e-8 4 #define pi acos(-1.0) 5 6 using namespace std; 7 typedef long long LL; 8 9 const int inf = 0x3f3f3f3f; 10 11 template<class T>inline void read(T &res) 12 { 13 char c;T flag=1; 14 while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; 15 while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; 16 } 17 18 const int maxn = 2e5 + 7; 19 20 int n, q; 21 22 int cnt, w[maxn], head[maxn], nxt[maxn], edge[maxn]; 23 int ans = 0; 24 25 int f[107][107]; 26 27 void BuildGraph(int u, int v, int c) { 28 ++cnt; 29 edge[cnt] = v; 30 nxt[cnt] = head[u]; 31 head[u] = cnt; 32 w[cnt] = c; 33 } 34 35 void dfs(int u, int fa) { 36 for ( int i = head[u]; i; i = nxt[i] ) { 37 int v = edge[i]; 38 if(v == fa) { 39 continue; 40 } 41 dfs(v, u); 42 for ( int j = q; j; --j ) { 43 for ( int k =j - 1; k >= 0; --k ) { 44 f[u][j] = max(f[u][j], f[u][j - k - 1] + f[v][k] + w[i]); 45 // printf("f[%d][%d]:%d ",u, j, f[u][j]); 46 } 47 } 48 } 49 } 50 51 int main() 52 { 53 read(n); read(q); 54 for ( int i = 1; i <= n - 1; ++i ) { 55 int u, v, w; 56 read(u); read(v); read(w); 57 BuildGraph(u, v, w); 58 BuildGraph(v, u, w); 59 } 60 dfs(1, 1); 61 for ( int i = 1; i <= n; ++i ) { 62 ans = max(f[i][q], ans); 63 } 64 ans = f[1][q]; 65 cout << ans << endl; 66 return 0; 67 }