acm小菜鸟的日常更新啊~~~
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1053
题目比较长,大致意思是说一个英文字母占四个字节,一个二进制数占一个字节,让你求如果一个字符串用哈夫曼树表示所需的字节数。
Sample Input
AAAAABCD
THE_CAT_IN_THE_HAT
END
Sample Output
64 13 4.9
144 51 2.8
AAAAABCD,若以这个字符串建哈夫曼树
字符串A出现了五次,B,C,D各出现了一次
B,C,D出现次数最少,放在最下面,依次类推
图中2代表孩子节点1与1的和,该哈夫曼树的权值为2+3+8=13;
可用优先队列实现,每次选出队列开头的两个元素(最小元素),
出队列,用ans加上最小元素的和,再将两最小元素的和放入队列中。
如果你以为这样就可以ac的话,那么,你错了!!!
还有一种边界条件!!!!!!!!!!整个字符串只出现一种字符的情况下,没有出队和入队,也无需建哈夫曼树,此时权值为字符串的长度,权重为8.0
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
using namespace std;
int main()
{
string s;
map<char,int> m;
while(cin>>s && s!="END")
{
m.clear();
priority_queue <int,vector<int>,greater<int> > q;
for(int i=0; i<s.length(); i++)
{
m[s[i]] ++;
}
if(m.size() == 1)
{
printf("%d %d 8.0\n",s.length()*8,s.length());
}//整个字符串只出现一种字符的边界条件,此种情况需要单独考虑
else
{
for(map<char,int>::iterator it=m.begin(); it!=m.end(); it++)
{
q.push(it->second);
//使用map记录字符个数,map的第二个元素即是字符个数
}
int ans = 0;
while(q.size()!=1)
{
int a=q.top();
q.pop();
int b=q.top();
q.pop();
ans = ans+a+b;
//统计最小的两个节点的和
q.push(a+b);
//将结果重新压入队列
}
printf("%d %d %.1f\n",s.length()*8,ans,(double)s.length()*8/ans);
}
}
return 0;
}