【BZOJ】4198荷马史诗-霍夫曼编码/优先队列

题解

关于Huffman Coding:

霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种。
霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

因为每个结点代表一个信息,不会出现一个编码是另一个编码的前缀的情况,保证了信息传递的准确性,又因为按此方法构造的编码表总长度最小(出现频率高的长度小,低的长度大),所以保证了数据的最小化(压缩)。

此题就是构造K进制下的huffman树,把所有数以结点值为该数,高为0的形式push到优先队列里,如果填不满,我们就加入相应个数的值为0,高为0的数到优先队列里。
排序第一关键字为权值降序,第二关键字为树高升序。
每次取k个出来,push一个值为K个数之和,高为 max(h[i]+1)(1ik) m a x ( h [ i ] + 1 ) ( 1 ≤ i ≤ k ) 的结点。


代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n,k;ll ret,sum,cur,ans;

struct P{
   ll v;int h;
   bool operator<(const P&u)const{
      return v==u.v?h>u.h:v>u.v;
   }
}tp;
priority_queue

Q; char ch; inline ll rd() { ch=getchar();ll x=0;int f=1; while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();} return x*f; } int main(){ int i,j,x,y; scanf("%d%d",&n,&k);tp.h=0; for(i=1;i<=n;++i){tp.v=rd();Q.push(tp);} x=(n-1)%(k-1); if(x) {n+=k-1-x;for(i=1;i<=k-1-x;++i){tp.v=0;Q.push(tp);}} n=(n-1)/(k-1); for(i=1;i<=n;++i){ cur=0;y=0; for(j=1;j<=k;++j){ cur+=Q.top().v;y=max(y,Q.top().h+1); Q.pop(); } tp.v=cur;tp.h=y; Q.push(tp); ans+=cur; } printf("%lld\n%d\n",ans,Q.top().h); }

你可能感兴趣的:(妙,霍夫曼编码,priority_queue)