基本技巧——哈夫曼树 学习笔记

news/2024/10/3 10:47:01

基本技巧——哈夫曼树 学习笔记

概念

一棵包含有 \(n\) 个叶子节点的 \(k\) 叉树,其中第 \(i\) 个叶子节点带有权值 \(W_i\)

树的带权路径长度,定义为从根结点到各叶结点的路径长度与相应叶节点权值的乘积之和。

树的带权路径长度,记为 WPL(Weighted Path Length of Tree),公式表示:

\[\text{WPL}=\sum_{i=1}^nW_iL_i \]

在一组有确定权值的叶子节点中,可以构造出不同的 \(k\) 叉树。

其中,WPL 最小的 \(k\) 叉树,称为 \(k\)哈夫曼树(Huffman 树)。

哈夫曼算法

容易发现,对于哈夫曼树,权值越小离根越远,反之,权值越大深度越小。

因此,容易得出,仅有叶子节点的度为 \(0\),其他节点的度均为 \(k\)

证明:如果其他节点的度小于 \(k\),那么意味着下面的节点放到这个空位,结果更优。

因此,我们需要额外添加一些权值为 \(0\) 的叶子节点,使得叶子节点个数 \(n\) 满足,

\[n-1\equiv0\pmod{k-1} \]

这样,我们就可以保证空的位置,会放在叶子上而不是非叶子节点,使得贪心正确。

算法流程

  • 初始化:将给定的 \(n\) 个叶子节点,直接连到根上,共 \(n+1\) 个节点。

  • 合并:从二叉树中选取两个权值和最小的节点,合并为一个新的节点。

  • 重复合并操作,直至只剩 \(k-1\) 个节点,所得二叉树即为哈夫曼树。

如果需要所得的最长编码最短,则还需要优先合并当前层数少的节点。

模板题

链接:P2168 [NOI2015] 荷马史诗。

模板题,模拟即可,

#include <bits/stdc++.h>using namespace std;constexpr int N = 1e5 + 10;using ll = long long;struct emm {ll w; int h;emm() = default;emm(ll w, int h): w(w), h(h) {}friend bool operator <(const emm &a, const emm &b) {return a.w == b.w ? a.h > b.h : a.w > b.w;}
};signed main() {ios::sync_with_stdio(false);cin.tie(nullptr), cout.tie(nullptr);int n, k; cin >> n >> k; priority_queue<emm> heap;ll w; for (int i = 1; i <= n; ++i) cin >> w, heap.emplace(w, 1);while ((heap.size() - 1) % (k - 1) != 0) heap.emplace(0, 1);ll ans = 0; auto merge = [&] {int h = 0; ll w = 0;for (int i = 1; i <= k; ++i) h = max(h, heap.top().h), w += heap.top().w, heap.pop();ans += w, heap.emplace(w, h + 1);};while (heap.size() >= k) merge();cout << ans << endl << heap.top().h - 1 << endl;return 0;
}

简单题

链接:P1090 [NOIP2004 提高组] 合并果子。

容易发现,合并顺序即叶子节点的深度,于是哈夫曼编码。

权值小的节点优先合并即可,代码:

#include <bits/stdc++.h>using namespace std;signed main() {ios::sync_with_stdio(false);cin.tie(nullptr), cout.tie(nullptr);int n; cin >> n;priority_queue<int, vector<int>, greater<int>> d;for (int i = 0, x; i < n; ++i) cin >> x, d.push(x);int ans = 0;while (d.size() > 1) {int a = d.top(); d.pop();int b = d.top(); d.pop();ans += a + b, d.push(a + b);}cout << ans << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44626.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

盘点 Spring Boot 解决跨域请求的几种办法

熟悉 web 系统开发的同学,对下面这样的错误应该不会太陌生。之所以会出现这个错误,是因为浏览器出于安全的考虑,采用同源策略的控制,防止当前站点恶意攻击 web 服务器盗取数据。 01、什么是跨域请求 同源策略,简单的说就是当浏览器访问 web 服务器资源时,只有源相同才能正…

基于正点原子ZYNQ7020的RTSP摄像头视频流获取

记录如何修改,编译定制化petalinux镜像,实现PS端和PL端互通硬件描述 硬件需求ZYNQ7020 系列 LCD 显示屏 800*600rtsp 网口摄像头接线方式USB_UART 通过 type-c 线连接电脑,电脑需要安装 CH340 的串口驱动 ps 端网口和摄像头的网口连接 开发板和摄像头的电源线连接 LCD 显示屏的…

移动平台开发综合实践 安卓android大作业-雷net在线对战

转自我的安卓课程作业 图片应该是没了,懒得搞了目录移动平台开发综合实践 大作业-雷net在线对战一、实验目的二、实验环境三、实验内容与实验要求3.1实验内容:雷net在线对战3.1.1棋盘3.1.2棋子3.1.3终端卡3.2原理分析3.3具体实验要求四、实验过程与分析4.1实验记录4.1.1 Sock…

解析Html Canvas的卓越性能与高效渲染策略

一、什么是Canvas 想必学习前端的同学们对Canvas 都不陌生,它是 HTML5 新增的“画布”元素,可以使用JavaScript来绘制图形。 Canvas元素是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。Canvas 由…

怎么控制多个存储设备的访问权限?数据安全存储方案来了

数据安全存储是指将数据以安全的方式存储在存储系统中,以确保数据的机密性、完整性和可用性。要控制数据安全存储的权限以保障安全,可以采取以下措施:访问控制列表(ACLs):使用ACLs来定义对存储数据的访问权限。ACLs允许你为每个文件或目录指定哪些用户或组有权访问它们,…

GPT-4o 只是对话式 Al 的冰山一角,背后隐藏了哪些新机会?(内含福利) | 编码人声

「编码人声」是由「RTE开发者社区」策划的一档播客节目,关注行业发展变革、开发者职涯发展、技术突破以及创业创新,由开发者来分享开发者眼中的工作与生活。 听友福利 欢迎在小宇宙播客评论区留言,分享你对 GPT-4o 的看法,或者对最有潜力的对话式 AI 场景的预测。我们将抽出…

一个开源的快速准确地将 PDF 转换为 markdown工具

大家好,今天给大家分享的是一个开源的快速准确地将 PDF 转换为 markdown工具。 Marker是一款功能强大的PDF转换工具,它能够将PDF文件快速、准确地转换为Markdown格式。这款工具特别适合处理书籍和科学论文,支持所有语言的转换,并且能够去除页眉、页脚等干扰元素,格式化表格…

简单聊聊Unicode

接下来我们简单讲讲,Unicode 的原理,例如,Unicode 的设计思路,Unicode 和 UTF 的关系等。接下来我们简单讲讲,Unicode 的原理,例如,Unicode 的设计思路,Unicode 和 UTF 的关系等。 ‍ 简单的字符编码模型 一个字符,在计算机中如何存储,是涉及到很多部分的。例如,一个…