1074. 二叉苹果树(有依赖的背包问题)

mac2026-02-21  9

1074. 二叉苹果树

有一棵二叉苹果树,如果树枝有分叉,一定是分两叉,即没有只有一个儿子的节点。

这棵树共 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; }

 

 

 

最新回复(0)