曾经沧海难为水,除却巫山不是云。|

Joey-Wang

园龄:4年3个月粉丝:17关注:0

9.8 哈弗曼树

9.8 哈弗曼树

http://codeup.hustoj.com/contest.php?cid=100000617

C 哈弗曼树

image-20200827215058546

题目解析

⚠️ 树的带权路径长度 = 叶子结点的带权路径长度之和
求树的最小带权路径 = 求哈弗曼树的带权路径

大体思路:

  • 使用优先队列,先将所有叶子结点都压入队列中
  • 每次从优先队列中取出两个最小的数,将它们相加后压入优先队列(在外部定义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编码

image-20200827215351252

题目解析

1️⃣ 使用优先队列实现哈弗曼树的构造:

  1. 先将所有叶子结点都压入队列中
  2. 每次从优先队列中取出两个权值最小的树,将它们组合成一棵树后压入优先队列,直到优先队列中只剩下个根结点root

2️⃣ 使用DFS完成哈夫曼的编码,使用map完成字符到编码的映射

  1. DFS左孩子时,编码code+“0”
  2. DFS右孩子时,编码code+“1”
  3. 死胡同——无左右孩子【因为哈弗曼树没有度为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

image-20200827220031070

题目解析

这道题实际就是求树的最小带权路径,即哈夫曼树的带权路径长度,也即叶子结点的带权路径长度之和

代码

#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 中国大陆许可协议进行许可。

posted @   Joey-Wang  阅读(63)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开