本题本质就是霍夫曼树!
霍夫曼树是一种带权路径长最短的二叉树,又叫做最优二叉树,常处理符号编写工作。
假设我们要给一个英文单字"F O R G E T"进行霍夫曼编码,每个英文字母出现的频率分别为2、3、4、4、5、7。
根据整组数据中符号出现的频率高低,决定如何给符号编码。如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长。
1.构树
(1) 将w1、w2、…,wn看成是有n 棵树的森林(初始每棵树仅有一个结点); (2) 在森林中选出两个根结点的权值最小的树合并,且新树的根结点权值为其左、右子树根结点权值之和; (3) 从森林中删除(2)中选取的两棵树,并将新树加入森林; (4) 重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
2.编码
(1) 给霍夫曼树的所有左链接编码为'0'、右链接为'1'。
(2) 从树根至树叶依序记录所有字母的编码。对应此题,比如长度27的棍子,需要分割成2、5、7、13。则每次分割都要保证子树又是一个哈弗曼树。
结果为27+14+7 = 48。
//最小堆实现霍夫曼树 #include <iostream> #include <algorithm> #include <cstring> #include <queue> #define INF 0x3f3f3f3f #define NMAX 105 using namespace std; int n, x, ans, a[NMAX]; //1. 写成模板 template<class T> using min_heap = priority_queue<T, std::vector<T>, std::greater<T>>; min_heap<int> my_min_heap; //2. 自定义比较结构 struct cmp{ bool operator () (int &a, int &b){ //int类型 return a > b; //min_heap } }; priority_queue<int, vector<int>, cmp> pq; //3. greater原理同2 priority_queue<int,vector<int>, greater<int>> pq1; int main(){ while (cin>>n){ ans = 0; for (int i = 0; i < n; ++i) { cin>>x; pq.push(x); } //最小堆实现霍夫曼树 while (pq.size() > 1){ int a = pq.top();pq.pop(); int b = pq.top();pq.pop(); ans += a+b; pq.push(a+b); } cout<< ans <<endl; } return 0; }水过,通过做题复习知识也挺好,现在来看学过的东西感觉更清晰。讲真、
