哈夫曼树
标签: 机试攻略 - 高分篇
学习人数: 22.1k


高清播放
赞赏支持

基本概念

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

 

哈夫曼树题目一般有以下几种考点

1、直接要求构造哈夫曼树,输出WPL,即带权路径长度。
2、考察概念的理解,如下面的例题,合并果子。
3、考察哈夫曼编码


 

合并果子
题目描述:
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。 因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。 例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
输入描述:
输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
输出描述:
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
输入样例#:

1 2 9
输出样例#:
15
题目来源:
DreamJudge 1544

题目解析:同学们读了这个题以后,大概都能想到,想要求得最小值必然是每次合并最小两个元素即可。然后一看输入样例,就认为只要从小到大排个序即可,然后从前往后依次合并。实际上这个方法是错误的,随手就能举出一个反例,5,6,7,8这四个数,如果先合并5和6,然后再和7合并,然后再和8合并这样得到的结果就会偏大,正确的方法是先合并5和6,然后再合并7和8,最后11和15合并在一起,这样才是最优解。为什么呢?因为在合并的过程中产生的新的数不一定是最小的,所以在每一次合并的过程中我们都需要重新排序找出当前最小的两个数。但是如果每一次合并就要重新全部排序,复杂度太高,不能接受。于是,我们就想到了使用优先队列来维护单调性,问题就解决了。

 

参考代码

#include <bits/stdc++.h>  
using namespace std;  
  
struct node {  
    int x;  
    node(int a) {x = a;}//构造函数方便赋值  
};  
  
//定义优先队列的比较关系 和sort的cmp类似  
bool operator < (const node& a, const node& b ){  
    return a.x > b.x;  
}  
  
int main()  
{  
    priority_queue<...
登录查看完整内容


课后作业

练习题目

DreamJudge 1382 哈夫曼树
DreamJudge 1562 哈夫曼编码


登录后开始许愿

1 条上岸许愿
咚咚常常
2024年3月8日 16:18

加油,一定考入中科大!

赞(3)