最优树适用: 当多个物体各自带有权值(不同的出现频率),要对每个物体进行编码,以使得每个物体的权值 * 该物体编码长度之和最小(即最多出现的物体编码最短),且每个物体的编码不能是其他物体编码的前缀。这时可使用哈夫曼树(最优二叉树)求解。
最优多叉树: 一般的哈夫曼树为二进制,当需要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;
}