http://acm.hdu.edu.cn/showproblem.php?pid=1053
/*
**利用优先队列构造霍夫曼树,首先将所有编码出现次数作为叶子节点的权值加入队列,
**然后每次取出权值最小的两个节点,组合后加入队列。
**最后遍历树求得总的编码长度。
*/
#include <iostream>
#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
struct node
{
int w;
bool yezi;//是否是叶子节点
node *lc,*rc;
bool operator< (const node &t) const//重载操作符,设定优先级
{
return t.w < w;
}
}a,b,c,*plc,*prc;
int arr[31];
int cmp(void const *a,void const *b){
return *(int *)b - *(int *)a;
}
priority_queue<node> Q;//优先队列
void HTree()
{
a = Q.top(); Q.pop();
while(!Q.empty())
{
b = Q.top(); Q.pop();
plc = new node();
prc = new node();
plc->w = a.w;plc->yezi = a.yezi; plc->lc = a.lc; plc->rc = a.rc;
prc->w = b.w;prc->yezi = b.yezi; prc->lc = b.lc; prc->rc = b.rc;
c.w = a.w + b.w;
c.yezi = false;
c.lc = plc;
c.rc = prc;
Q.push(c);
a = Q.top(); Q.pop();
}
}
int LOT(node *T, int step)
{
if(T->yezi) {return step*T->w;}
return LOT(T->lc,step+1)+LOT(T->rc,step+1);
}
int main(){
string s;
while(cin>>s,s!="END")
{
memset(arr, 0, sizeof(arr));
while(!Q.empty()) Q.pop();
int i,sum=0;
for(i=0; i<s.size(); i++)
arr[s[i]-'A']++;
qsort(arr,31,sizeof(arr[0]),cmp);
if(arr[1]==0)//只有一种编码
{
printf("%d %d 8.0\n",8*arr[0],arr[0]);
continue;
}
for(i=0; i<31&&arr[i]!=0; i++)
{
a.w = arr[i];
a.yezi = true;
a.lc = a.rc = NULL;
Q.push(a);
}
HTree();
sum = LOT(&a, 0);
printf("%d %d %.1f\n",8*s.size(),sum,(8.0*s.size())/sum);
}
return 0;
}