[算法]Huffman树(哈夫曼树)
一、关于Huffman树
Huffman树(哈夫曼树)可以解决下述问题:
- 一颗\(n\)个叶节点的\(k\)叉树,第\(i\)个叶节点的权值为\(w_i\),现在欲求\(\sum w_i\times l_i\)的最小值,其中\(l_i\)表示第\(i\)个叶子节点到根结点的距离。
二、具体实现
为了保证\(\sum w_i\times l_i\)最小,我们应该保证权值越大的叶节点深度越小。可以看出,这是很简单的贪心思想。
特殊地,我们可以先从二叉Huffman树开始研究。二叉Huffman树的实现过程如下:
1.构造一个小根堆,依次插入这\(n\)个节点的权值。
2.从堆内依次取出权值最小的两个节点\(w_1,w_2\),令\(ans+=w_1+w_2\)。
3.把\(w_1+w_2\)作为新的节点\(w_3\),并插入到堆中。此时\(w_3\)为\(w_1,w_2\)的父亲节点。
4.重复上述操作,直到堆的大小等于1。
Huffman树并没有真正的建立一棵树,只是在操作的时候形成一棵树的结构。
下图是二叉Huffman树的具体执行过程:最终ans=33。

for(int i=1;i<n;i++){//n个数,操作(n-1)次
int x=q.top();q.pop();
int y=q.top();q.pop();
q.push(x+y);
ans+=x+y;
}
例1:P1090 合并果子
分析:
因为多多每次合并消耗的体力等于要合并的两堆果子的重量之和,所以最终消耗的体力就是每堆果子的重量\(\times\)合并的次数。这正符合Huffman树能解决的问题类型。
代码如下:
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;//小根堆
int a[10010],ans;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
q.push(a[i]);
}
while(n!=1){//重复操作直到只剩下一个节点
int x=q.top();q.pop();
int y=q.top();q.pop();
q.push(x+y);
ans+=x+y;
n--;
}
printf("%d",ans);
return 0;
}
现在我们由二叉延伸到k叉Huffman树。此时将每次取出的2个数改为k个数。这时存在一个问题,在最后一次取值时,剩余的节点可能不足以取出k个。显然这样不是最优解,当我们任取Huffman树中一个深度最大的节点,并改为树根的子节点,此时\(\sum w_i \times l_i\)就会更小。
因此只有我们补加一些额外的空节点,并将这些空节点放置在最底层时才能保证贪心算法的正确性。
当\((n-1)mod(k-1)\neq 0\)时,我们还需要补充\((k-1)-(n-1)mod(k-1)\)个节点保证等式\((n-1)mod(k-1)=0\)成立。
例2:P2168 [NOI2015]荷马史诗
分析:
这道题构造的编码方式其实就是Huffman编码,我们把单词出现的次数作为Huffman树的叶节点的权值,然后求出k叉Huffman树即可。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
ll h,w;
bool operator <(const node &other)const{
return (w!=other.w)? w>other.w:h>other.h;
}
};
priority_queue<node> q;
int n,k,sum;
ll t,ans;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&t);
q.push((node){1,t});
}
if((n-1)%(k-1)) sum=(k-1)-(n-1)%(k-1);
for(int i=1;i<=sum;i++) q.push((node){1,0});
sum+=n;
while(sum!=1){
ll partw=0,maxh=0;
for(int i=1;i<=k;i++){
node now=q.top();q.pop();
partw+=now.w;
maxh=max(maxh,now.h);
}
ans+=partw;
q.push((node){maxh+1,partw});
sum-=(k-1);
}
printf("%lld\n%lld",ans,q.top().h-1);
return 0;
}

[算法]Huffman树(哈夫曼树)的更多相关文章
- Huffman Tree (哈夫曼树学习)
WPL 和哈夫曼树 哈夫曼树,又称最优二叉树,是一棵带权值路径长度(WPL,Weighted Path Length of Tree)最短的树,权值较大的节点离根更近. 首先介绍一下什么是 WPL,其 ...
- 树-哈夫曼树(Huffman Tree)
概述 哈夫曼树:树的带权路径长度达到最小. 构造规则 1. 将w1.w2.-,wn看成是有n 棵树的森林(每棵树仅有一个结点): 2. 在森林中选出根结点的权值最小的两棵树进行合并,作为一棵新树的左. ...
- 【算法】赫夫曼树(Huffman)的构建和应用(编码、译码)
参考资料 <算法(java)> — — Robert Sedgewick, Kevin Wayne <数据结构> ...
- [C++]哈夫曼树(最优满二叉树) / 哈夫曼编码(贪心算法)
一 哈夫曼树 1.1 基本概念 算法思想 贪心算法(以局部最优,谋求全局最优) 适用范围 1 [(约束)可行]:它必须满足问题的约束 2 [局部最优]它是当前步骤中所有可行选择中最佳的局部选择 3 [ ...
- 经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)
参考网址: https://www.jianshu.com/p/cb5af6b5096d 算法导论--最小生成树 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. im ...
- 哈夫曼树(三)之 Java详解
前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:htt ...
- 哈夫曼树(二)之 C++详解
上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...
- 哈夫曼树(一)之 C语言详解
本章介绍哈夫曼树.和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可.若 ...
- 哈夫曼树——c++
哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树. 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树. 这个定 ...
随机推荐
- Python实现一个ORM模型类
ORM是三个单词首字母组合而成,包含了Object(对象-类),Relations(关系),Mapping(映射).解释过字面意思,但ORM的概念仍然模糊.私以为要理解一个事物,最好的法子是搞明白它出 ...
- LoadRunner录制HTTPS协议脚本
学习LoadRunner录制HTTPS协议脚本,其实是一个意外的收获.当我拿到要测试的URL时,我像以前的步骤一样录制脚本,但是录制结束后,发现并没有生成脚本,开始以为是LoadRunner的原因,我 ...
- 深入Redis命令的执行过程
深入Redis命令的执行过程 Redis 服务器: Redis 服务器实现与多个客户端的连接,并处理这些客户端发送过来的请求,同时保存客户端执行命令所产生的数据到数据库中.Redis 服务器依靠资源管 ...
- 单调栈-Maximum Width Ramp
2020-01-23 19:39:26 问题描述: 问题求解: public int maxWidthRamp(int[] A) { Stack<Integer> stack = new ...
- JSON字符串带BOM头"ufeff"
调用三方接口返回值JSON字符串带BOM头"\ufeff",JSON解析死活报错. 我是用SpringBoot的RestTemplate调用三方接口的,一开始返回值我是用对象接收返 ...
- Java 添加、删除Excel表单控件
通过表单控件,用户可以快速地将数据填写到模板文档中,轻松引用单元格数据并与其进行交互.本文通过Java代码示例介绍如何在Excel表格中添加表单控件,包括文本框.单选按钮.复选框.组合框.微调按钮等: ...
- 使用Python+OpenCV进行图像处理(二)| 视觉入门
[前言]图像预处理对于整个图像处理任务来讲特别重要.如果我们没有进行恰当的预处理,无论我们有多么好的数据也很难得到理想的结果. 本篇是视觉入门系列教程的第二篇.整个视觉入门系列内容如下: 理解颜色模型 ...
- war 和 war exploded
IDEA 开发项目时,部署 tomcat 的 Deployment 选项出现: war 模式 可以称之为发布模式.先将 WEB 工程打成 war 包,然后再将其上传到服务器进行发布. war expl ...
- Crash
一.Crash类型 crash 一般产生自 iOS 的微内核 Mach,然后在 BSD 层转换成 UNIX SIGABRT 信号,以标准 POSIX 信号的形式提供给用户.NSException 是使 ...
- 学习笔记-EL
仅作为学习过程中笔记作用,若有不正确的地方欢迎指正 目标 理解El的作用,熟练使用EL EL表达式与Jsp表达式对比来记 EL表达式的概念,作用,语法 Jsp作用主要是用来实现动态网页的,而动态网页中 ...