news 2026/10/26 16:59:17

蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:哈夫曼树与合并果子解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:哈夫曼树与合并果子解析

哈夫曼树(Huffman Tree)与"合并果子"是信息学竞赛里最经典、也最容易拿满分的贪心模型之一。它几乎每年都出现在各大青少年编程赛事中:第十八届蓝桥杯全国软件和信息技术大赛软件赛正处于报名季(C/C++ 程序设计、Python 程序设计 科目报名 2026-10-08 10:00—12-18 14:00,省赛/全国选拔赛定于 2027 年 4 月);中国电子学会 2026 年 12 月青少年软件编程等级考试(C/C++ 一级至十级、Python 一级至六级)报名 9/23—12/2、12-12 统考;全国青少年信息素养大赛算法应用赛项也把"贪心 + 优先队列"列为高频考点。本文用一道原创题,带你把哈夫曼贪心吃透。

一、题目:校园科技节物资搬运——合并果子

食堂后山堆放着 n 堆果子,第 i 堆质量为 w_i。每次可以挑选任意两堆合并成一堆,这次合并消耗的体力等于这两堆质量之和。合并后得到的新堆可以继续参与后续合并,直到所有果子合成一堆。求最小的体力总消耗。

输入:第一行 n,第二行 n 个整数 w_1…w_n。
输出:一个整数,表示最小体力消耗。

样例输入:

5 3 4 5 2 1

样例输出:

33

提示:合并顺序不同,总消耗差异巨大。比如[100,1,1,1]如果按输入顺序硬合(100+1=101,101+1=102,102+1=103)总消耗高达 306;而先合并轻的(1+1=2,1+2=3,3+100=103)只要 108。

二、核心考点

  1. 贪心策略的正确性:为什么"每次都合并当前最轻的两堆"一定最优?
  2. 优先队列(小根堆):如何高效、动态地取出全局最小的两个元素。
  3. 与哈夫曼树 / 带权路径长度(WPL)的等价关系:总消耗 = 哈夫曼树的带权路径长度。
  4. 数据范围与溢出:果子数量多、单堆质量大时,总消耗会远超int范围,必须用long long(C++)或 Python 自带大整数。

三、解法拆解

思路

把每一堆果子看作一个节点,初始有 n 个节点,每个节点权值 = 果子质量。每次选权值最小的两个节点 x、y 合并,产生一个新节点,权值为 x+y,并把 x+y 累加到总消耗里。新节点重新放回候选集合,继续选最小的两个……直到只剩一个节点。

为什么贪心正确?用交换论证一句话理解:在任意一棵合并树里,质量最小的两个果子一定会在最底层(深度最大)被合并——如果最优解中它们没在一起,把一次合并换成合并这两个最轻的,总代价只会更小或不变。所以"每次合并最轻两堆"不会丢最优性。

样例一步步推演(w = [1, 2, 3, 4, 5])

  • 取 1、2 合并 → 新堆 3,消耗3;候选 {3, 3, 4, 5}
  • 取 3、3 合并 → 新堆 6,消耗6;候选 {4, 5, 6}
  • 取 4、5 合并 → 新堆 9,消耗9;候选 {6, 9}
  • 取 6、9 合并 → 新堆 15,消耗15;只剩一堆

总消耗 = 3 + 6 + 9 + 15 =33✅

C++ 解法

#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; if (!(cin >> n)) return 0; // 小根堆:每次取出最小的两个 priority_queue<ll, vector<ll>, greater<ll>> pq; for (int i = 0; i < n; i++) { ll x; cin >> x; pq.push(x); } if (pq.size() <= 1) { cout << 0 << "\n"; return 0; } ll ans = 0; while (pq.size() > 1) { ll a = pq.top(); pq.pop(); ll b = pq.top(); pq.pop(); ll s = a + b; // 本次合并的体力消耗 ans += s; // 累加 pq.push(s); // 新堆放回,参与后续合并 } cout << ans << "\n"; return 0; }

Python 解法

import heapq def huffman_cost(w): if len(w) <= 1: return 0 h = w[:] heapq.heapify(h) # Python 的 heapq 默认就是小根堆 ans = 0 while len(h) > 1: a = heapq.heappop(h) b = heapq.heappop(h) s = a + b ans += s heapq.heappush(h, s) return ans n = int(input()) w = list(map(int, input().split())) print(huffman_cost(w))

四、时间与空间复杂度

  • 时间复杂度:每个元素进出优先队列各约 O(log n) 次,总共O(n log n)。
  • 空间复杂度:优先队列存放所有堆,最坏O(n)。

对比朴素做法(每次把数组排序取前两个再插回去)是 O(n² log n),数据一大就会超时;而优先队列把"取最小"优化到了对数级。

五、七大易错点

  1. 用int存总消耗溢出:n 和 w 都大时,累计和轻松超过 2³¹,C++ 一定要用long long;Python 无此烦恼(自动大整数)。
  2. 误用大根堆:C++ 的priority_queue默认是大顶堆,必须写成priority_queue<ll, vector<ll>, greater<ll>>;Python 的heapq默认小顶堆,正好契合。
  3. n = 1 没特判:只有一堆果子时消耗为 0,直接输出,别进循环(虽然进循环也安全,但显式特判更清晰)。
  4. 忘了把新堆 push 回去:合并出的新堆必须重新入堆,否则后续合并会漏掉它,答案偏小。
  5. 按输入顺序硬合而非动态取最小:a[0]+a[1]再+a[2]…… 这种"顺序合并"在[100,1,1,1]上会算出 306,而正确哈夫曼是 108。必须每一步都重新取全局最小两堆。
  6. 多组测试未清空堆 / 重置答案:用全局变量时,每组数据前要pq = priority_queue<...>()重新构造,或ans = 0。
  7. 用sort每轮取前二:看似简单,实则是 O(n² log n),大数据必 TLE。记住——动态最小两堆用优先队列,不是反复排序。

六、进阶拓展

  1. 哈夫曼编码:把"果子质量"换成"字符出现频率",合并过程就是构造最优前缀编码树,带权路径长度 WPL 最小即总编码长度最短。这是压缩算法(zip、JPEG)的理论基础。
  2. 每次合并 k 堆:若规定每次最多合并 k 堆,需先补若干质量为 0 的"虚拟堆",使(n-1) % (k-1) == 0,否则最后一次凑不齐 k 堆会导致非最优。
  3. WPL 的另一种算法:总消耗 = Σ(每堆质量 × 它在合并树中的深度)。叶子越轻,应当被压得越深。
  4. 正确性证明(交换论证):假设最优合并树中质量最小的两个果子不在同一底层,把某次合并替换为合并这两个最小的,可证明总代价不增——这就是贪心不会错过最优解的本质。
  5. 别和 OBST 搞混:最优二叉搜索树(已知查找概率)用的是区间 DP(经典"石子合并"思路),与哈夫曼不同;哈夫曼只关心合并代价、不关心中序顺序。

七、小结与互动

哈夫曼合并是"贪心 + 优先队列"的标杆题:每次合并最轻两堆,用一个小根堆 O(n log n) 搞定,答案就是哈夫曼树的带权路径长度。牢记 long long 防溢出、小根堆方向、动态取最小三点,蓝桥杯与电子学会考级基本稳拿。

思考题:如果规定每次必须合并恰好 3 堆,最少体力该怎么算?欢迎在评论区留下你的思路,下期我们可以一起拆解"k 路合并"的虚拟堆补零技巧。

如果觉得这篇对你有帮助,点个赞 + 收藏,关注我,持续更新少儿编程竞赛原创题与双语言题解。


📚 免费少儿编程资料(夸克网盘领取)

以下资料来自夸克网盘分享,点击链接可直接保存;若需在 App 内打开,也可复制下方明文链接:

  1. 全国青少年信息素养大赛复赛集训题目Python&C++.docx
    https://pan.quark.cn/s/93995d3cb150
  2. 2024信息素养-智能算法应用挑战赛-复赛初中组题目7月7日.pdf
    https://pan.quark.cn/s/da97b5dbf75d
  3. Python背记手册.pdf
    https://pan.quark.cn/s/7568ae9ca92b
  4. Python课程
    https://pan.quark.cn/s/a94bf02d00c6
  5. 2024信息素养大赛图形化复赛集训题答案3-9
    https://pan.quark.cn/s/6ccab7ec3cbc
  6. 2025年03月份电子学会考级真题
    https://pan.quark.cn/s/4403c4228912
  7. 2025全国青少年信息素养大赛赛项说明
    https://pan.quark.cn/s/d9d0df4a9f29
  8. 青少儿信息素养大赛编程资料
    https://pan.quark.cn/s/4ab6bd83be8a

资料持续更新,关注获取最新分享。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 16:58:43

南瑞101规约C代码解析:从RTU101.rar到报文调试实战

简介&#xff1a;这份资源围绕IEC 101规约与南瑞101实现展开&#xff0c;面向电力自动化方向的开发者、RTU调试人员及电力系统通信协议学习者&#xff0c;帮助理解远动通信中RTU与主站之间的数据交互机制。压缩包为rar格式&#xff0c;共2个文件&#xff0c;包含1个cpp源码与1个…

作者头像 李华
网站建设 2026/10/26 16:56:59

人物音色档案加音频参考:构建统一且有辨识度的AI角色声音

一、为什么要看这份榜单 AI角色声音制作通常包含几个连续环节&#xff1a;确定人物设定、建立声音方向、准备音频参考、生成台词、结合画面和剧情进行调整。如果这些环节彼此割裂&#xff0c;常见问题包括&#xff1a; 同一角色在不同片段中音色变化明显&#xff1b;角色的年龄…

作者头像 李华
网站建设 2026/10/26 16:56:57

t3code:TypeScript+Tailwind+tRPC+Codegen跨端开发范式

1. 项目概述&#xff1a;t3code 是什么&#xff0c;它解决哪类开发者的实际痛点&#xff1f;t3code 这个名字乍看像某个新出的 CLI 工具或开源项目代号&#xff0c;但结合当前全网搜索热度与高频共现词——CLI、Electron、web app、iOS——它并非一个已发布、有官方文档的成熟产…

作者头像 李华
网站建设 2026/10/26 16:56:06

有限反馈预编码详解:从SVD到DFT码本与MMSE接收的完整实现

简介&#xff1a;面向MIMO无线通信与有限反馈预编码学习者的Matlab仿真资源包&#xff0c;围绕SVD预编码、MMSE接收机、DFT码本与码本设计展开&#xff0c;适合通信工程与电子信息类专业学生、研究人员对照学习。压缩包内共9个文件&#xff0c;以4个.m脚本和5个.mat数据文件为主…

作者头像 李华
网站建设 2026/10/26 16:54:38

AI Agent循环工程实战:手写Loop Engineering避免死循环与失控

写AI Agent最让人头疼的是什么&#xff1f;不是Prompt写不好&#xff0c;也不是模型选不对——而是你明明给了它一堆工具和任务&#xff0c;它却在执行过程中反复调用同一个工具&#xff0c;或者在一个环节里绕来绕去&#xff0c;最后既没完成任务&#xff0c;也没告诉你发生了…

作者头像 李华
网站建设 2026/10/26 16:54:23

开源版workbuddy替代:基于Rust与MCP的Agent工作台实战

1. 从“workbuddy 替代”这个念头说起&#xff1a;我到底想解决什么问题最早动这个念头&#xff0c;是因为我在好几个项目里反复遇到同一个尴尬场景&#xff1a;团队里有人在用 workbuddy 这类工作台工具管理日常任务、文档和 Agent 调用&#xff0c;但一旦涉及私有化部署、数据…

作者头像 李华