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

题解

关于Huffman Coding

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

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

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


代码

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cctype>
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<P>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);
}


猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80594996
今日推荐