哈夫曼树:带权路径长度最短的树,保证权值越大深度尽量越小。
思路:题意转化过来就是求一个k叉哈夫曼树,同时记录最大深度。题目中的编码方式被称为哈夫曼编码。同一层的k个分支上面的字符分别是0~k-1,也能看做是一颗字典树。
题目中的任意一个单词都不会是另一个单词的前缀在字典树里面就是,每一个单词编码的末尾都在叶节点上。
要使深度最小可以额外记录一个变量h,每次取k个元素时若权值相同优先选深度小的。
这里如果单词数量不够会在最后导致没有k个元素可取,所以要补0进去。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef long long ll;
struct node
{
ll w,h;
bool operator < (node a) const
{
if(w!=a.w) return w>a.w;
else return h>a.h;
}
};
priority_queue<node>heap;
int n,k;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
ll a;
cin>>a;
heap.push({a,1});
}
while((n-1)%(k-1)!=0)
{
heap.push({0,1});
n++;
}
ll sum=0;
while(heap.size()>1)
{
ll sum1=0,cnt1=0;
for(int i=1;i<=k;i++)
{
sum1+=heap.top().w;
cnt1=max(cnt1,heap.top().h);
heap.pop();
}
sum+=sum1;
heap.push({sum1,cnt1+1});
}
cout<<sum<<endl;
cout<<heap.top().h-1<<endl;
return 0;
}