1018. A Binary Apple Tree
Memory Limit: 16 MB
2 5 \ / 3 4 \ / 1
Input
Output
Sample
input | output |
---|---|
5 2 1 3 1 1 4 10 2 3 20 3 5 20 |
21 |
这道题目是说,我们有一颗苹果树,该苹果树除了叶子节点以外的每个节点都分为两枝。每个节点使用 1 到 N 进行编号,其中根节点的编号为 1。每一枝上有若干苹果。为了方便采摘苹果,现在我们要对该苹果进行剪枝,要求剪去指定数目的枝条后,使被剪去的苹果数量最少。我们的任务就是求剪枝后该苹果树上还剩下多少个苹果。
输入的第一行包含两个数:N 和 Q (1 ≤ Q ≤ N; 1 < N ≤ 100)。 N 代表苹果树的节点数。Q 代表剪枝后该苹果树上还剩下多少树枝。剩下的 N−1 行用于描述树枝。每行包含三个整数。头两个整数代表节点编号,第三个整数代表该树枝上的苹果的数目。
输出只包含一个数,表示剪枝后该苹果树上还剩下的苹果的数目。注意,剪树时要保留该苹果树的根。
在程序中第 39 到 59 行的 Read 方法读取输入。
第 61 到 80 行的 Build 方法使用广度优先搜索算法读取的输入以建立苹果树。
第 82 到 94 行的 Solve 方法使用动态规划算法来计算剪枝后的苹果树上还剩下多少苹果。注意题目中允许 Q 的最大值为 N,实际 Q 的最大值应该是 N - 1。所以第 93 行使用了 Math.Max 方法以处理 Q = N 的情况。
注意在程序中节点的编号改为从 0 到 N - 1。
下面是用题目中所给的输入例子,程序运行时的状态:
最后,源程序代码如下:
2 using System.IO;
3
4 namespace Skyiv.Ben.Timus
5 {
6 // http://acm.timus.ru/problem.aspx?space=1&num=1018
7 sealed class T1018
8 {
9 struct Element
10 {
11 int to, cnt, next;
12
13 public int To { get { return to; } }
14 public int Cnt { get { return cnt; } }
15 public int Next { get { return next; } }
16
17 public Element(int to, int cnt, int next)
18 {
19 this.to = to;
20 this.cnt = cnt;
21 this.next = next;
22 }
23 }
24
25 static void Main()
26 {
27 new T1018().Run(Console.In, Console.Out);
28 }
29
30 void Run(TextReader reader, TextWriter writer)
31 {
32 Element[] buf;
33 int[] vec, sz, edge;
34 var q = Read(reader, out vec, out buf);
35 var kid = Build(vec, buf, out sz, out edge);
36 writer.WriteLine(Solve(q, kid, sz, edge));
37 }
38
39 int Read(TextReader reader, out int[] vec, out Element[] buf)
40 {
41 var ss = reader.ReadLine().Split();
42 var n = int.Parse(ss[0]);
43 var q = int.Parse(ss[1]);
44 buf = new Element[(n - 1) * 2];
45 vec = new int[n];
46 for (var i = 0; i < n; i++) vec[i] = -1;
47 for (int k = 0, i = 1; i < n; i++)
48 {
49 ss = reader.ReadLine().Split();
50 var a = int.Parse(ss[0]) - 1;
51 var b = int.Parse(ss[1]) - 1;
52 var cnt = int.Parse(ss[2]);
53 buf[k] = new Element(b, cnt, vec[a]);
54 vec[a] = k++;
55 buf[k] = new Element(a, cnt, vec[b]);
56 vec[b] = k++;
57 }
58 return q;
59 }
60
61 int[,] Build(int[] vec, Element[] buf, out int[] sz, out int[] edge)
62 {
63 var kid = new int[vec.Length, 2];
64 var qz = new int[vec.Length];
65 sz = new int[vec.Length];
66 edge = new int[vec.Length];
67 for (int k = 1, n = 0, i = 0; i < k; i++, n = 0)
68 {
69 sz[qz[i]] = -1;
70 for (var j = vec[qz[i]]; j != -1; j = buf[j].Next)
71 {
72 if (sz[buf[j].To] == -1) continue;
73 kid[qz[i], n++] = buf[j].To;
74 edge[buf[j].To] = buf[j].Cnt;
75 qz[k++] = buf[j].To;
76 }
77 if (n == 0) sz[qz[i]] = 0;
78 }
79 return kid;
80 }
81
82 int Solve(int q, int[,] kid, int[] sz, int[] edge)
83 {
84 var dp = new int[sz.Length, sz.Length];
85 for (var c = sz.Length - 1; c >= 0; c--)
86 {
87 if (sz[c] == 0) continue;
88 sz[c] = sz[kid[c, 0]] + sz[kid[c, 1]] + 2;
89 Do(dp, kid, sz, edge, c, 0);
90 Do(dp, kid, sz, edge, c, 1);
91 Do(dp, kid, sz, edge, c);
92 }
93 return dp[0, Math.Max(0, sz.Length - 1 - q)];
94 }
95
96 void Do(int[,] dp, int[,] kid, int[] sz, int[] edge, int c, int k)
97 {
98 for (var i = 0; i <= sz[kid[c, k]]; i++)
99 {
100 var j = i + sz[kid[c, 1 - k]] + 1;
101 var m = dp[kid[c, k], i] + edge[kid[c, k]];
102 if (dp[c, j] < m) dp[c, j] = m;
103 }
104 }
105
106 void Do(int[,] dp, int[,] kid, int[] sz, int[] edge, int c)
107 {
108 for (var i = 0; i <= sz[kid[c, 0]]; i++)
109 for (var j = 0; j <= sz[kid[c, 1]]; j++)
110 {
111 var m = dp[kid[c, 0], i] + dp[kid[c, 1], j] + edge[kid[c, 0]] + edge[kid[c, 1]];
112 if (dp[c, i + j] < m) dp[c, i + j] = m;
113 }
114 }
115 }
116 }
返回目录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述