2168 荷马史诗
这道题,听说过,因为这个题的名字挺奇葩,还是来练贪心
不过这个题是一个哈夫曼树,比较恶心
哈夫曼树我们也学过,哈夫曼树又叫最优二叉树
我们按照思路就是求一个k进制的哈夫曼编码,平时我们说的哈夫曼为是2进制的,构造的方法很容易,本题也可以用相同的思想
维护什么呢?转换题意,我们要维护的是最短的带权路径和哈夫曼树的高度,然后就是如何维护
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define LL long long
using namespace std;
struct node
{
LL w,h;
node(LL W, LL H)
{
w=W,h=H;
}
};
bool operator<(node a, node b)
{
if(a.w!=b.w) return a.w>b.w;
return a.h>b.h; //如果长度相等,高度小的优先
} //构造小根堆的操作。
priority_queue<node> q; //优先队列
int n,k,cnt;
LL temp,maxh,ans;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++)
{
scanf("%lld",&temp);
q.push(node(temp,1));
}
if((n-1)%(k-1) != 0) cnt=k-1-(n-1)%(k-1); //判断是否要补空节点
for (int i=1; i<=cnt; i++)
q.push(node(0,1)); //补空节点
cnt+=n; //cnt为根节点个数(最初每个根节点都为其本身)
while(cnt>1)
{
temp=maxh=0;
for(int i=1; i<=k; i++)
{
temp+=q.top().w;
maxh=max(maxh,q.top().h);
q.pop();
}
ans+=temp; //维护带权路径长度之和
q.push(node(temp, maxh+1)); //合并,高度为最高子树高度+1
cnt-=k-1; //减少根节点
}
printf("%lld\n%lld\n",ans,q.top().h-1);
return 0;
}