哈夫曼树:

一棵包含n个叶子节点的k叉树,其中第i个叶子节点带有权值w[i], l[i]为该点到根节点的距离,求所有叶子节点的w[i]*l[i]之和的最小值。

二叉哈夫曼树的求解:

对于二叉哈夫曼树的求解,我们贪心的将最小的两个节点放到最远,然后合并那两个节点,新的点的权值为那两个节点的和,放入原序列中,重复上述步骤,直到原序列只剩下一个节点,这棵树就构建好了,下面有个例子

例如: 3 4 5 8 , 设最后答案为ans

首先我们选3 4, 合并节点,新点权值为7,并加入原序列,ans+= (3+4)

然后新序列中合并5和7,新点权值为12    ans+=(5+7)

最后合并12 和 8  新节点为20,跳出循环  ans+=(12+8)

最后的哈夫曼树就是右边黑色的那棵树,答案就是ans

对于某一个节点,因为其被合并之后的值给了新的节点,而新的节点合并的时候又会加上这个值,实际上是不断为答案作贡献的,做贡献次数就等于深度(也就是路径长度)

k叉哈夫曼树的求解:

对于k(k>2)叉哈夫曼树,其求解思路和2叉类似。

我们合并2叉哈夫曼树是从子节点一路合并到根节点的,结束合并操作的标志就是序列中只剩下一个数。但是对于k叉哈夫曼树这会出现问题。

因为最大的节点应该优先连在根节点上,而我们求解时又是从叶子节点开始,这会造成最后根节点的子树少于k个,这是不对的。

比如: 3叉哈夫曼树,序列:3 4 5 8

第一次合并,合并3 4 5.

第二次合并,合并剩下的,最后这棵树就是:

这显然不是最优解。

因此对于k叉哈夫曼树,为了保证其根节点可以选到k个子树,假设节点个数为n,需要满足(n-1)mod(k-1)==0 的条件,假如不满足,我们为原序列补0

对于3 4 5 8 , 它就变成 3 4 5 8 0

第一步合并3 4 0 ,新节点为7,新序列: 7 5 8

然后合并7 5 8

最后生成的树:

例题1: ch1701

题目链接:https://www.acwing.com/problem/content/150/

这就是一棵裸的二叉哈夫曼树,每合并一次相当于最后答案计算的时候多加一份,就相当于在边长为1的哈夫曼树中更深一层

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 7;
int heap[maxn];
int cnt;
void del() {swap(heap[1], heap[cnt--]);int now = 1, to = 2;while (to <= cnt) {if (to<cnt&&heap[to]>heap[to + 1]) to++;if (heap[to] >= heap[now]) break;swap(heap[to], heap[now]);now = to;to = now << 1;}
}
void insert(int x) {heap[++cnt] = x;int now = cnt;while (now > 1) {if (heap[now >> 1] <= heap[now]) break;swap(heap[now], heap[now >> 1]);now >>= 1;}
}
int main() {int n; cin >> n;for (int i = 1; i <= n; i++) {int inp;scanf("%d", &inp);insert(inp); //我用二叉堆维护每次选最小值}int ans = 0;int min1, min2;while (cnt > 1) {min1 = heap[1];del();min2 = heap[1];del();ans += min1 + min2;insert(min1+min2);}cout << ans << endl;return 0;
}

例题2:bzoj4198

https://www.lydsy.com/JudgeOnline/problem.php?id=4198

每种编码方式前缀不同可以联想到字典树,此时每一个叶子节点就代表一个编号。

可以将哈夫曼树看成这样的字典树,而对于每个单词最后的贡献为: 单词哈希后长度*出现次数 ,对应到哈夫曼树里面就是 子节点权值=出现次数 , 深度=单词哈希后长度。

最后还要让最长的哈希最短,也就是要这颗哈夫曼树最深的子节点最浅,因此我们在合并的时候,假如遇到权值一样的,优先和深度小的合并(不要让深度大的继续合并下去了)

具体操作的话我们可以使用优先队列(当然堆都一样),然后用一个pair存 ,pair.first= 节点的权值  pair.second=节点的深度,优先队列按照first排,first一样再按second排

这就是一棵k叉哈夫曼树

#include<bits/stdc++.h>
#define ll long long
using namespace std;
typedef pair<ll, int> P;
const int INF = 0x3f3f3f3f;
struct cmp {bool operator()(const P p1, const P p2) {if (p1.first != p2.first) return p1.first > p2.first;else return p1.second > p2.second;}
};
priority_queue<P, vector<P>, cmp> Q;
int main() {ll ans = 0;int n, k;cin >> n >> k;for (int i = 1; i <= n; i++) {ll inp;scanf("%lld", &inp);Q.push(P(inp,0));}while ((n - 1) % (k - 1) != 0) { //k叉哈夫曼树补0Q.push(P(0, 0));n++;}while (Q.size() > 1) {P p = Q.top();Q.pop();for (int i = 2; i <= k; i++) { //每次取k,然后合并P p1 = Q.top();Q.pop();p.first += p1.first;p.second = max(p.second, p1.second); }p.second++;//深度为子节点里最深的+1ans += p.first;Q.push(p);}P p = Q.top();cout << ans << endl << p.second << endl;
}

哈夫曼树(Huffman树) 学习日记 + 例题(ch1701 bzoj4198)相关推荐

  1. 数据结构C#版笔记--啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)

    哈夫曼树Huffman tree 又称最优完全二叉树,切入正题之前,先看几个定义 1.路径 Path 简单点讲,路径就是从一个指定节点走到另一个指定节点所经过的分支,比如下图中的红色分支(A-> ...

  2. 贪心算法【区间调度】【背包问题】【集合覆盖】【旅行商问题】【哈夫曼构造价值树】

    贪心算法  在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解.  贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择, ...

  3. 数据压缩之经典——哈夫曼编码(Huffman)

    (笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的教学视频,使用时请注意 ...

  4. 哈夫曼算法(huffman algorithm C)

    哈夫曼算法:树的权值*路径相加最小. #include<stdio.h> #define size 10 typedef struct huffman {int weight;int lc ...

  5. 哈夫曼(Huffman)编码在word2vec中的应用

    哈夫曼(Huffman)编码 假设给定 n 个权值{w1,w2,...,wn}作为二叉树的 n 个叶子结点,若二叉树的带权路径长度达到最小, 则称这样的二叉树为最优二叉树,也称为 Huffinan 树 ...

  6. 霍夫曼树:霍夫曼编码(Huffman Tree:Huffman Coding)

    一.简介 霍夫曼树常处理符号编写工作.根据整组数据中符号出现的频率高低,决定如何给符号编码.如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长. 相关术语 路径:从书中一个节点到另一个节点之 ...

  7. 【数据结构】哈夫曼编码和树

    新知识: 转载博客:http://blog.163.com/sdnu_et/blog/static/13184636920100574953335/ 哈夫曼树:建一棵树,使每个叶子节点的点权与深度的乘 ...

  8. 哈夫曼编码(Huffman)Java实现代码简化版

    这个网上发现的Huffuman编码Java实现在组织上相对简化,便于理解文件压缩过程:提取文件统计字符频度-根据字符频度创建huffman树-根据huffman树生成huffman可变字长无前缀编码- ...

  9. python哈夫曼编码注意_Python 算法(2) 哈夫曼编码 Huffman Encoding

    这个问题原始是用来实现一个可变长度的编码问题,但可以总结成这样一个问题,假设我们有很多的叶子节点,每个节点都有一个权值w(可以是任何有意义的数值,比如它出现的概率),我们要用这些叶子节点构造一棵树,那 ...

最新文章

  1. 中小型局域网规划实战案例
  2. 并发编程——线程——Thread对象的属性和方法
  3. .NET Core 部署IIS无法启动Hangfire方案
  4. [Leetcode][第111题][JAVA][BFS][二叉树的最小深度][BFS][递归]
  5. 淘宝网架构分享总结[转]
  6. python3.8入门教程完整版_Python 3.8从入门到精通(视频教学版)
  7. SQL入门基础视频教程-Visual Foxpro视频教程
  8. 测试方法——正交表法
  9. 数据库导出Excel乱码 解决
  10. 海思Hi3796MV200最新官方SDK
  11. [TF进阶] 循环神经网络
  12. 显卡mx150和230哪个好_MX130与MX150差距对比分析
  13. 基于BS架构的微博系统
  14. 大数据下的密码学技术挑战
  15. Sentence Centrality Revisited for Unsupervised Summarization
  16. 四十二、Fluent欧拉模型流化床模拟
  17. 日志(Logger)
  18. ffmpeg缩放视频尺寸
  19. 计算机视觉之图像分割——水平集方法_ACWE2001
  20. 年产2万吨山楂酒工厂的设计-装瓶工段及车间的设计(lunwen+任务书+开题+选题表+cad图纸)

热门文章

  1. Win11 安装WSA(安卓子系统)指南
  2. 2022施工员-土建方向-岗位技能(施工员)操作证考试题库及答案
  3. Adb push 文件夹到手机目录上
  4. 2022年最新优化算法---蛛母狼马蜂算法(论文创新点)
  5. xmind序列码激活亲测可用版本
  6. 算法模型部署上线工程实践
  7. 蓝桥杯 ALGO-40算法训练 会议中心 (APIO 2009)
  8. 4项目管理--项目整合管理
  9. python能做什么兼职-学会Python有哪些可以做的兼职?
  10. 第一次视频面试-欢聚时代PHP实习生-广州-附超详细对话