标签:poj1521 hdu1053 entropy 哈夫曼编码 huffman
#include <stdio.h>
int main()
{
puts("转载请注明出处谢谢");
puts("http://blog.csdn.net/vmurder/article/details/43020921");
}
题意:
输出字符串的长度*8、huffman编码长度、两者比值。
题解:
huffman编码:
我们发现对于一个字符串,如果我们把它变成01串,比如ABCDE
那么我们需要
A : 000
B : 001
C : 010
D : 100
E : 101
来表示每一个字符,然后识别的时候就是每三个一识别。
这种编码叫定长编码。
显然对于一个串,它的定长编码长度是串长*定长。
但是其实它可以更短。
如果我们想要识别一个串,就需要所有字符的编码都不为其它编码的前缀,这样才可以成功解码。
而此时我们可以根据出现频率来构造huffman编码,以达到最优解。
构造方法可以见于黑书P245,毕竟它还是很水的,随便看看就能明白。
下面是我要讲的方法:
这种编码最后可以构成一颗二叉树,每个叶子节点都是一种字符,而它的变长编码(Huffman)就是从root到这个节点经过的边的序号序列,而左儿子边序号标0,右儿子边序号标1。
建树方法:先把所有字符按照出现次数作为关键字排序,然后给最小的两个赋一个父亲,然后把这两个叶子节点弹出优先队列,把父亲插入进去,父亲的关键字是儿子的size之和。
最后只剩下一个节点的时候停止。
证明在黑书上有,自己去翻吧,感性的思考一下就是每个点都有深度,然后∑深度*size=ans,
我们需要让size大的深度尽量小。
呃,虽然上面的证明显然是在chedan,但是,,并没有但是。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1000
using namespace std;
char s[N];
int cnt[N];
priority_queue<int>q;
int ans,len;
int main()
{
freopen("test.in","r",stdin);
int i,j,k;
while(scanf("%s",s)!=EOF)
{
while(!q.empty())q.pop();
len=strlen(s),ans=0;
if(len==3&&s[0]=='E'&&s[1]=='N'&&s[2]=='D')return 0;
memset(cnt,0,sizeof cnt);
for(i=0;s[i];i++)cnt[s[i]]++;
for(i=0;i<N;i++)if(cnt[i])q.push(-cnt[i]);
for(;;)
{
i=q.top(),q.pop();
if(q.empty())break;
j=q.top(),q.pop();
ans-=(i+j);
q.push(i+j);
}
if(!ans)ans=len;
printf("%d %d %.1lf\n",len*8,ans,(double)len*8/(double)ans);
}
return 0;
}
【POJ1521】【HDU1053】Entropy 哈夫曼(Huffman)编码
标签:poj1521 hdu1053 entropy 哈夫曼编码 huffman
原文地址:http://blog.csdn.net/vmurder/article/details/43020921