• 哈夫曼树学习笔记


    定义

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

    应用

    信息传递中的编码问题:使编码长度尽可能短又不产生歧义。

    歧义:两个编码有公共前缀部分,比如: (001) , (0010)

    构造方法

    1. 设有 n 个树,初始时每颗树只有一个叶子节点(有权值),代表一种编码情况,权值代表出现次数。

    2. 每次选取权值和最小的两颗树,将它们合并成一棵树,新树权值和为原来两颗树权值之和。

    3. 重复 2. 直至只有一颗树。即为哈夫曼树。

    实现方法

    我们可以用小根堆堆来维护权值最小的树,利用贪心求解。

    例题

    题目

    洛谷 P2168 [NOI2015]荷马史诗

    思路

    这道题要求构造 (k) 叉哈夫曼树,并使树的高度最小,并输出其高度

    因为每次减少 (k-1) 个树,最后有些节点可能为空,应该补上一些空节点。

    同时排序时要注意当权值相同时,让高度小的树排在后面。

    代码

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <queue>
    #include <vector>
    
    #define re(x) read(x)
    #define ll long long
    #define mes(x) memset(x,0,sizeof(x))
    #define il inline
    #define _for(i,a,b) for(int i = (a);i < (b);i++)
    #define _rep(i,a,b) for(int i = (a);i <= (b);i++)
    
    using namespace std;
    
    template <typename T>
    il void read(T &x){
    	x = 0;
    	T sgn  = 1;
    	char ch = getchar();
    	for(;!isdigit(ch);ch = getchar()) if(ch == '-') sgn = -1;
    	for(;isdigit(ch);ch = getchar()) x = (x<<1) + (x<<3) +(ch^48);
    	x *= sgn;
    }
    
    template <typename T>
    il void write(T x){
    	if(x<0) x = -x , putchar('-');
    	if(x == 0) putchar(48);
    	int cccnt = 0 , a[70];
    	while(x>0) {
    		a[++cccnt] = x%10;
    		x /= 10;
    	}
    	for(int i = cccnt;i > 0;i--) putchar(a[i]+48);
    	putchar('
    ');
    	return;
    }
    
    int n,k,cnt;
    ll ans;
    
    struct root{
        ll tot,h;
        bool operator < (const root &b) const {
            if(tot == b.tot) return h > b.h;
            return tot > b.tot;
        }
    };
    
    priority_queue <root> q;
    
    int main (){
        re(n); re(k);
        _for(i,0,n){
            ll w;
            re(w);
    		q.push((root){w,0});
    	}
    	if((n-1)%(k-1) != 0){
    		cnt += k-1 - (n-1)%(k-1);
    		_for(i,0,cnt)
    			q.push((root){0,0});
    	}
    	cnt = n;
    	while(cnt > 1){
    		ll maxn = 0 ,tot = 0;
    		_for(i,0,k){
    			tot += q.top().tot;
    			maxn = max(maxn,q.top().h);
    			q.pop();
    		}
    		ans += tot;
    		q.push((root){tot,maxn+1});
    		cnt -= k-1;
    	}
    	write(ans);
    	write(q.top().h);
    	return 0;
    }
    
  • 相关阅读:
    基于gdal库用C++实现将shp文件转成geojson文件
    阅读《计算机图形学编程(使用OpenGL和C++)》
    阅读《计算机图形学编程(使用OpenGL和C++)》4
    解决PUBG启动时报某个必须的文件出现问题
    变电站RHEL5.8使用
    maven 引入了jar包,但却不能使用jar包里类
    创建虚拟环境(virtualenvwrapper)
    django 1.0 跨域问题及解决
    python 信号处理
    celery 报错: Received unregistered task of type ‘xxxxxx...’
  • 原文地址:https://www.cnblogs.com/werner-yin/p/13302003.html
Copyright © 2020-2023  润新知