[荷马史诗] — k叉哈夫曼树
作者:互联网
题目背景
追逐影子的人,自己就是影子 ——荷马
题目描述
输入格式
输出格式
输入输出样例
【说明/提示】
【数据规模与约定】
题意分析
依据题意,就是要求构造一个K进制的赫夫曼编码。
我们需要求的是树的WPL和该赫夫曼树的高度。所以在struct里面不仅要记录结点的w,还要记录深度h,并以他们作为小根堆的关键字。
对于k叉赫夫曼树的求解,直观的想法是在贪心的基础上,改为每次从堆中去除最小的k个权值合并。我们便可以按照赫夫曼树的构造方式,将当前最小的K个节点合并为1个父节点(显然,可以使用优先队列(二叉堆)进行维护),直至只有一个父节点。
注意一个细节,如果在执行最后一次循环时,堆的大小在(2~k-1)之间(不足以取出k个),那么整个赫夫曼树的根的子节点个数就小于k,也就表明了最靠近根节点的位置反而没有被排满,这显然不是最优解 。因此,我们应该在执行上述贪心算法之前,补加一些额外的权值为0的叶子节点,使叶子节点的个树满足(n-1)%(k-1)=0。
- 如果k=2,构建传统的二叉赫夫曼树。堆维护即可。
- 如果k>2,当(n-1)%(k-1)!=0的时候会出现最后一次合并的结点数少于k个,需要增加空节点。
1 // K阶的赫夫曼树 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 //#define ll long long 8 using namespace std; 9 10 //定义结点结构体 11 struct node { 12 int w,h; //w为权重,h为高度 13 node() {w = 0, h=0;} 14 node(int w, int h): w(w), h(h) {} 15 bool operator <(const node &a)const{ //重载运算符,使w小的结点先出队列 16 return a.w == w ? h>a.h : w>a.w; //优先考虑权值,其次考虑高度 17 } 18 }; 19 20 int ans; 21 22 priority_queue<node>q; //类型为node的优先队列 23 24 int main() { 25 int n,k; 26 cin>>n>>k; 27 for(int i = 1; i <= n; i++) { 28 int w; 29 cin>>w; 30 q.push(node(w,1)); //默认h=11,这里进行强制类型转换 31 } 32 while((q.size()-1) % (k-1) !=0 ) { //需要添加空节点的情况 33 q.push(node(0,1)); //空节点默认w=0,h=1 34 } 35 while(q.size()>=k) { 36 int h = -1; 37 int w = 0; 38 for(int i = 1; i <= k; ++i) { //每次选出最小的k个结点 39 node t = q.top(); 40 q.pop(); 41 h = max(h,t.h); 42 w += t.w; 43 } 44 ans += w; 45 q.push(node(w, h + 1)); 46 } 47 48 cout<<ans<<endl; 49 cout<<q.top().h-1<<endl; 50 51 system("pause"); 52 return 0; 53 }
标签:node,哈夫曼,荷马史诗,int,权值,include,节点,夫曼 来源: https://www.cnblogs.com/zhcnfyy/p/15383055.html