///题目的大致意思是给你一个大写字母和下滑线组成的字符串,先计算出字符串在内存中实际占用的字节数,每个char占用8个字节
///然后通过huffman编码后字符串所占的字节数,两者相除即可
#include <cstdio>
#include <cstring>#include <queue>
using namespace std;
#define MAX 50010///题目为给出字符串的长度,所以此处分配的尽量大一点
char s[MAX];
int len;
int v[256];///压缩
int ans;
struct node
{
int num;
int cnt;
int lchild;
int rchild;
friend bool operator<(node a,node b);
}tree[MAX*2];
bool operator<(node a,node b)
{
return a.cnt>b.cnt;/// cnt越小优先权越大
}
priority_queue<node> q;
void dfs(int root,int h);
int built_tree();
int main()
{
while(scanf("%s",s)==1&&strcmp(s,"END")!=0)
{
len=strlen(s);
memset(v,0,sizeof(v));
for(int i=0; i<len; i++)
{
int tmp=(int)s[i];
v[tmp]+=1;
}
int root=built_tree();
ans=0;
if(root!=0)/// 临界情况:只有一钟字符时的情况。当时做这道题目是未考虑这种情况,导致wrong answer
{
dfs(root,0);
ans/=2;
}
else
ans=tree[0].cnt;
printf("%d %d %.1f\n",len*8,ans,(double)len*8/ans);
}
return 0;
}
int built_tree()建立huffman树
{
while(!q.empty())
q.pop();
int pos=0;
for(int i=0; i<255; i++)
if(v[i]!=0)
{
tree[pos].num= pos;///此处应该理清关系
tree[pos].cnt= v[i];
tree[pos].lchild=-1;
tree[pos].rchild=-1;
q.push(tree[pos]);
pos++;
}
while(!q.empty()) ///此处大忌,当时多加了一个;导致死循环,debug时超级郁闷
{
node t1=q.top();
q.pop();
if(q.empty())
return t1.num;
node t2=q.top();
q.pop();
tree[pos].num=pos;
tree[pos].cnt=t1.cnt+t2.cnt;
tree[pos].lchild=t1.num;
tree[pos].rchild=t2.num;
if(q.empty())
return pos;
q.push(tree[pos]);
pos++;
}
}
void dfs(int root,int h)///通过深搜找到每个子节点的深度即编码长度,累加求和
{
if(tree[root].lchild==-1)
ans+=(tree[root].cnt*h);
else
dfs(tree[root].lchild,h+1);
if(tree[root].rchild==-1)
ans+=(tree[root].cnt*h);
else
dfs(tree[root].rchild,h+1);
}
总结:1、临界情况需要仔细考虑
2、细节问题while();
3、熟悉优先队列的使用方法