哈夫曼树,最优二叉树,最优多叉树

最优树适用: 当多个物体各自带有权值(不同的出现频率),要对每个物体进行编码,以使得每个物体的权值 * 该物体编码长度最小(即最多出现的物体编码最短),且每个物体的编码不能是其他物体编码的前缀。这时可使用哈夫曼树(最优二叉树)求解。

最优多叉树: 一般的哈夫曼树为二进制,当需要k进制时,每次选取最小的k个节点合并为一个节点即可,但此时可能出现最顶层反而没有填充满(不是最优解)的情况。可用添加 k-1-(n-1)%(k-1) 个空节点(权值为0)来占取最底层,把其他节点挤到更优的位置上去。(n为节点数,k为进制数)

时间复杂度:可能是 O(nlogn)

参考:哈夫曼树原理
重载如何使用指针作为参数

例题:P2168 [NOI2015]荷马史诗 (k进制最优多叉树)

可以查询路径的模板:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;

struct NODE
{
    long long deep,h;
    long long w;
    vector<NODE*>son;
    NODE():deep(0),w(0){}
};

struct CMP{
    bool operator() (NODE* &a,NODE* &b)const{
        if(a->w==b->w){return a->h >= b->h;}
        return a->w > b->w;
    }
};

long long n,k,w,tot=0,maxdeep;
NODE* root;

priority_queue<NODE*,vector<NODE*>,CMP>q;

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        NODE* node=new NODE();
        cin>>(*node).w;
        q.push(node);
    }
    long long temp=(n-1)%(k-1);
    if(temp!=0)temp=k-1-temp;
    for(int i=1;i<=temp;i++){NODE* node=new NODE();node->w=0;q.push(node);}

    while(!q.empty())
    {
        NODE* newnode=new NODE();
        for(int i=1;i<=k;i++){
            NODE* now=q.top();q.pop();
            newnode->w+=now->w;
            newnode->son.push_back(now);
            newnode->h=max(newnode->h,now->h+1);
        }
        if(q.size()==0){root=newnode;break;}
        q.push(newnode);
    }

    queue<NODE*>q2;
    root->deep=0;
    q2.push(root);
    while(!q2.empty()){
        NODE* now=q2.front();q2.pop();
        for(auto& i:now->son){
            i->deep=now->deep+1;
            if(i->son.size()==0&&i->w!=0){tot+=i->deep*i->w;maxdeep=i->deep;}
            q2.push(i);
        }
    }

    cout<<tot<<endl;cout<<maxdeep<<endl;

    return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值