有一棵二叉蘋果樹,如果樹枝有分叉,一定是分兩叉,即沒有隻有一個兒子的節點。
這棵樹共 N 個節點,編號爲 1 至 N,樹根編號一定爲 1。
我們用一根樹枝兩端連接的節點編號描述一根樹枝的位置。
一棵蘋果樹的樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少蘋果。
這裏的保留是指最終與1號點連通。
輸入格式
第一行包含兩個整數 N 和 Q,分別表示樹的節點數以及要保留的樹枝數量。
接下來 N−1 行描述樹枝信息,每行三個整數,前兩個是它連接的節點的編號,第三個數是這根樹枝上蘋果數量。
輸出格式
輸出僅一行,表示最多能留住的蘋果的數量。
數據範圍
1≤Q<N≤100.
N≠1,
每根樹枝上蘋果不超過 30000 個。
輸入樣例:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
輸出樣例:
21
分析:這是一道有依賴的揹包問題,如果要選擇當前節點,則必須選擇它的父節點
有一點需要注意,在決策那一層的循環中,k只能小於揹包體積j,因爲x選y的時候也需要選擇一條邊,原本x取了k條邊,加上多的,就是k+1條邊,所以x選j條邊,則需要再選擇j-(k+1)條邊,即j-k-1
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int n,m,tot;
int head[N],nexts[N*2],ver[N*2],edge[N*2];
int f[N][N];
void add(int x,int y,int z){
ver[++tot]=y,edge[tot]=z;
nexts[tot]=head[x],head[x]=tot;
}
void dp(int x,int father){
for(int i=head[x];i;i=nexts[i]){//物品組
int y=ver[i],z=edge[i];
if(y==father) continue;
dp(y,x);
for(int j=m;j>=0;j--){//體積
for(int k=0;k<j;k++){//決策
f[x][j]=max(f[x][j],f[x][j-1-k]+f[y][k]+z);
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n-1;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
dp(1,0);
printf("%d",f[1][m]);
return 0;
}