二叉苹果树

二叉苹果树

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

这棵树共 N 个节点,编号为 1N,树根编号一定为 1

我们用一根树枝两端连接的节点编号描述一根树枝的位置。

一棵苹果树的树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

这里的保留是指最终与 1 号点连通。

输入格式

第一行包含两个整数 NQ,分别表示树的节点数以及要保留的树枝数量。

接下来 N1 行描述树枝信息,每行三个整数,前两个是它连接的节点的编号,第三个数是这根树枝上苹果数量。

输出格式

输出仅一行,表示最多能留住的苹果的数量。

数据范围

1Q<N100.
N1,
每根树枝上苹果不超过 30000 个。

输入样例:

5 2
1 3 1
1 4 10
2 3 20
3 5 20

输出样例:

21

 

解题思路

  这是有依赖的背包问题的简化版。因为选择的树枝要和根节点连通,因此可以把每个节点看成是物品,如果要选择这个物品就一定要选择这个物品的根节点,因此就存在一个依赖关系。把每个边的价值转变到节点的价值,然后每个节点的体积都为1,就可以转化成有依赖的背包问题。

  用f(i,j)来表示在以i为根的子树中选择j条边的最大价值。把以i为节点的树的每一个子节点看成是各组物品,再根据各个物品组选择不同的边数进行状态转移。

  AC代码如下:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 110, M = N * 2;
 5 
 6 int n, m;
 7 int head[N], e[M], wts[M], ne[M], idx;
 8 int f[N][N];
 9 
10 void add(int v, int w, int wt) {
11     e[idx] = w, wts[idx] = wt, ne[idx] = head[v], head[v] = idx++;
12 }
13 
14 void dfs(int u, int pre) {
15     for (int i = head[u]; i != -1; i = ne[i]) {
16         if (e[i] != pre) {
17             dfs(e[i], u);
18             for (int j = m; j; j--) {
19                 for (int k = 0; k < j; k++) {
20                     f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e[i]][k] + wts[i]);
21                 }
22             }
23         }
24     }
25 }
26 
27 int main() {
28     scanf("%d %d", &n, &m);
29     
30     memset(head, -1, sizeof(head));
31     for (int i = 0; i < n - 1; i++) {
32         int v, w, wt;
33         scanf("%d %d %d", &v, &w, &wt);
34         add(v, w, wt), add(w, v, wt);
35     }
36     
37     dfs(1, -1);
38     printf("%d", f[1][m]);
39     
40     return 0;
41 }
复制代码

 

参考资料

  AcWing 1074. 二叉苹果树(算法提高课):https://www.acwing.com/video/416/

posted @   onlyblues  阅读(377)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示