·大致思路:
首先要了解哈夫曼树的一些概念:
①带权路径:每个叶子结点都有权值,对于某叶子结点来说,它的带权路径就是“结点权值*从根节点到该结点的路径长度”。
②哈夫曼树的构造方法:两个权值最小的叶子结点作为兄弟去构成一个非叶节点。(该父亲非叶节点的权值=二者之和)
之前我只知道这些基本概念,求带权路径和的时候也只是“数数”——数路径长度,乘上叶子结点权值。但是,其实求带权路径和还有更简单实用的方法!
对于这个哈夫曼树,可以知道,由于非叶节点之间是具有“包含”关系的,比如29=15+14=7+8+14,58=7+8+14+29,会发现,越往高走,越会重复累加一次下面的叶子结点,其实这就隐含体现了“路径长度”。
得出结论:哈夫曼树的带权路径和=非叶节点的权值之和。
同时,要记住的是:如何以O(nlogn)的时间复杂度实现哈夫曼树。
方法:优先队列模拟“小顶堆”,每次取出堆顶的两个最小的叶子结点组成一个非叶节点,sum+=非叶节点的权值。
优先队列默认是“大顶堆”,也就是top是最大的,而我们要用小顶堆,一直在递增~一直在greater~所以要写成:priority_queue<int, vector<int>, greater<int> >
·AC代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#include<queue>
priority_queue<int, vector<int>, greater<int> > q; //小顶堆实现哈夫曼树!记住写法
int n;
int main()
{
int x;
int sum=0;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
cin>>x;
q.push(x);
}
while(q.size()>1)
{
//找到两个最小的
int a=q.top();
q.pop();
int b=q.top();
q.pop();
q.push(a+b);
sum+=(a+b);
}
cout<<sum<<endl;
q.pop(); //清空根节点,准备迎接下一组数据
sum=0; //清空sum,准备迎接下一组数据
}
return 0;
}