哈夫曼树(周灵猪)

洛谷2168荷马史诗

#include
#include
#include
#include
#include
using namespace std;
typedef pair aii;
priority_queue, greater> que;
int n, k, Num = 0;
long long Length = 0, Ans = 0, x;
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        que.push(aii(x,1));//节点的权值,层数//初始时候每个节点都是第一层
    }
    if ((n - 1) % (k - 1) != 0)//
        Num = k - 1 - (n - 1) % (k - 1);//当结点不够时,插入值为零的虚节点,不然算出来可能不是最优解
    for (int i = 1; i <= Num; i++)//插入虚节点,其实就是因为完全二叉树的长度最长,所以要弄成完全二叉树那样,而不能像普通哈夫曼树
        que.push(aii(0,1));
    Num += n;//代表一共有多个元素
    while(Num != 1) 
    {
        aii a;
        long long Temp = 0, Max_h = 0;
        for (int i = 1; i <= k; i++) //几进制就是拿几个点,比如二进制子树可以有两个分别是0,1路径编号,要是三就是0,1,2,
        {
            a = que.top();
            Temp += a.first;//合并后的最大值
            Max_h = max(Max_h, a.second);//计算最大层数
            que.pop();
        }//合并前k个元素
        Ans += Temp;//最短长度就是每次合并后的值的和
        que.push(aii(Temp,Max_h+1));//层数加以
        Num -= k;//节点-k因为拿出去了多少个点
        Num++;//节点+1因为放回去了
    }
    Length = que.top().second - 1;
    cout << Ans << endl;
    cout << Length;
    return 0;
}

后面

这个是最优解的哈夫曼树就是完全K叉树的模样,如果不是要求最解其实很结点

每次都是将k个节点合并为1个(减少k-1个),一共要将n个节点合并为1个,如果(n-1)%(k-1)!=0 则最后一次合并时不足k个。也就表明了最靠近根节点的位置反而没有被排满,因此我们需要加入k-1-(n-1)%(k-1)个空节点使每次合并都够k个节点(也就是利用空节点将其余的节点挤到更优的位置上)。

你可能感兴趣的:(数据结构)