9.8 哈弗曼树
9.8 哈弗曼树
http://codeup.hustoj.com/contest.php?cid=100000617
C 哈弗曼树

题目解析
⚠️ 树的带权路径长度 = 叶子结点的带权路径长度之和
求树的最小带权路径 = 求哈弗曼树的带权路径
大体思路:
- 使用优先队列,先将所有叶子结点都压入队列中
- 每次从优先队列中取出两个最小的数,将它们相加后压入优先队列(在外部定义ans,将相加的结果累加),直到优先队列中只剩下一个元素
代码
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
int main() {
int n, a, b, temp, ans;
while (scanf("%d", &n) != EOF) {
priority_queue<int, vector<int>, greater<int>> q;
ans = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &temp);
q.push(temp);
}
while (q.size() > 1) {
a = q.top();
q.pop();
b = q.top();
q.pop();
q.push(a + b);
ans += a + b;
}
printf("%d\n", ans);
}
return 0;
}
D Haffman编码

题目解析
1️⃣ 使用优先队列实现哈弗曼树的构造:
- 先将所有叶子结点都压入队列中
- 每次从优先队列中取出两个权值最小的树,将它们组合成一棵树后压入优先队列,直到优先队列中只剩下个根结点root
2️⃣ 使用DFS完成哈夫曼的编码,使用map完成字符到编码的映射
- DFS左孩子时,编码code+“0”
- DFS右孩子时,编码code+“1”
- 死胡同——无左右孩子【因为哈弗曼树没有度为1的结点,故要么左右孩子都有,要么都没有】
代码
#include <cstdio>
#include <queue>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct node {
char d;
int w;
node *lchild;
node *rchild;
};
struct cmp {
// 权重w大的优先级低,权重相等时ACSII大的优先级低
bool operator()(node *a, node *b) {
if (a->w != b->w) return a->w > b->w;
else return a->d > b->d;
}
};
priority_queue<node *, vector<node *>, cmp> q;
map<char, string> ans;
node *createHaffmanTree(int n) {
node *a, *b, *sum, *temp;
for (int i = 0; i < n; i++) {
temp = new node;
cin >> temp->d >> temp->w;
temp->lchild = temp->rchild = NULL;
q.push(temp);
}
while (q.size() > 1) {
a = q.top();
q.pop();
b = q.top();
q.pop();
sum = new node;
sum->w = a->w + b->w;
sum->d = a->d; //满足题目中的小规定:创建的新节点所代表的字符与它的做孩子的字符相同
sum->lchild = a, sum->rchild = b;
q.push(sum);
}
return q.top();
}
void DFS(node *root, string code) {
if (root->lchild == NULL && root->rchild == NULL) {
ans[root->d] = code;
return;
}
if (root->lchild != NULL) DFS(root->lchild, code + "0");
if (root->rchild != NULL) DFS(root->rchild, code + "1");
}
int main() {
int n;
node *root;
while (scanf("%d", &n) != EOF) {
root = createHaffmanTree(n);
DFS(root, "");
for (map<char, string>::iterator it = ans.begin(); it != ans.end(); it++) {
cout << (*it).first << ":" << (*it).second << endl;
}
q.pop();
ans.clear();
}
return 0;
}
E 合并果子-NOIP2004TGT2

题目解析
这道题实际就是求树的最小带权路径,即哈夫曼树的带权路径长度,也即叶子结点的带权路径长度之和
代码
#include <cstdio>
#include <queue>
using namespace std;
int main() {
int n, temp, a, b, ans = 0;
priority_queue<int, vector<int>, greater<int>> q;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &temp);
q.push(temp);
}
while (q.size() > 1) {
a = q.top();
q.pop();
b = q.top();
q.pop();
q.push(a + b);
ans += a + b;
}
printf("%d\n",ans);
return 0;
}
本文作者:Joey-Wang
本文链接:https://www.cnblogs.com/joey-wang/p/14541189.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步