定义带权路径长度为:每个节点的权值*到根的距离 的和
当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。
构造哈夫曼树过程
每次找出权值最小的两个点作为一个新节点的左右儿子,把他们的权值和放回队列中,反复进行这个操作直到得到一个点为止
拓展到 k 叉树
如果把上述过程改为每次选出k个权值最小的贪心的话,会发现最后一次可能会不足k个而导致答案不优,可以通过补充若干0,使得总节点个数mod k-1 = 1
P2168 [NOI2015] 荷马史诗
多叉模板
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct point
{
ll w,h;
bool operator < (const point &oth) const
{
if(w==oth.w) return h>oth.h;
return w>oth.w;
}
};
priority_queue <point> q;
int n,k;
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d",&n,&k);
ll x,ans=0;
for(int i=1;i<=n;i++) scanf("%lld",&x),q.push((point){x,0});
while((q.size()-1)%(k-1)!=0) q.push((point){0,0});
while(q.size()>=k)
{
ll sum=0,mx=0;
for(int i=1;i<=k;i++)
{
mx=max(q.top().h,mx);
sum+=q.top().w;
q.pop();
}
q.push((point){sum,mx+1});
ans+=sum;
}
printf("%lld\n%lld\n",ans,q.top().h);
return 0;
}