题目:http://acm.hdu.edu.cn/showproblem.php?pid=1053
题意:每个编码都有哈夫曼和ascall两种。问该序列的哈夫曼长度和ascall长度以及比。
因为只需要长度,可以用优秀队列模仿建树过程,不需要建树。
还有就是注意cout表达小数点后一位的方法。
#include<bits/stdc++.h>
#define INF 1e18
#define inf 1e9
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int _max = 256;
int main(){
IOS;
string s;
int sum,cnt;
double rate;
int t[_max];
priority_queue<int,vector<int>,greater<int> > q;
while(cin>>s){
if(s == "END") break;
cnt = s.size();
memset(t,0,sizeof(t));
for(int i = 0 ; i < cnt ; i++)
++t[int(s[i])];
while(!q.empty()) q.pop();
for(int i = 0 ; i < _max ; i++)
if(t[i]) q.push(t[i]);
int k = q.size();
if(k == 1){
sum = q.top();
rate = 8.0;
}
else{
sum = 0;
int ch = 0;
while(--k){
ch = q.top(); q.pop();
ch += q.top() ; q.pop();
sum += ch;
q.push(ch);
}
rate = double(cnt*8.0)/double(sum);
}
cout<<cnt*8<<' '<<sum<<' '<<fixed<<setprecision(1)<<rate<<endl;
}
return 0;
}
建树方法:(不是自己打的。因为觉得很详细就直接copy了。)
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
#define MaxValue 0x7fff
struct HaffNode
{
int weight;
int parent; //仿指针
int left;
int right;
int flag; //标志是否加入到哈夫曼树中
};
int Haffman(const int weight[],int n) //构造哈夫曼树
{
int sumWeight = 0;
//一共有2n-1个节点
const int N = 2*n-1;
HaffNode* root = new HaffNode[N];
int i,j;
for(i=0;i<n;++i)//n个叶子节点
{
(root+i)->weight = weight[i];
(root+i)->parent = -1;
(root+i)->left = -1;
(root+i)->right = -1;
(root+i)->flag = 0;
}
for(i=n;i<N;++i)//n-1个非叶子节点
{
(root+i)->weight = 0;
(root+i)->parent = -1;
(root+i)->left = -1;
(root+i)->right = -1;
(root+i)->flag = 0;
}
int min1,min2; //两个最小权重值
int index1,index2;//两个最小权重值的下标
//构造n-1个非叶子节点
for(i=0;i<n-1;++i)
{
//找两个最小的
min1 = min2 = MaxValue;
index1 = index2 = 0;
for(j=0;j<n+i;++j)
{
if(root[j].weight < min1 && root[j].flag==0)
{
min2 = min1;
index2 = index1;
min1 = root[j].weight;
index1 = j;
}
else if(root[j].weight < min2 && root[j].flag==0)
{
min2 = root[j].weight;
index2 = j;
}
}
//将两个权值最小的树合并
root[index1].parent = n+i;
root[index2].parent = n+i;
root[index1].flag = 1;
root[index2].flag = 1;
root[n+i].weight = root[index1].weight + root[index2].weight;
root[n+i].left = index1;
root[n+i].right = index2;
sumWeight += root[n+i].weight; //只需要累加非叶子节点的权值
}
delete[] root;
return sumWeight;
}
int main()
{
string text;
int Size,i,j;
int data[256];
int letters[256];
double rate;
while(cin>>text)
{
if(text=="END") break;
Size = text.size();
memset(letters,0,sizeof(letters));
for(i=0;i<Size;++i)
++letters[static_cast<int>(text[i])];
j = 0;
memset(data,0,sizeof(letters));
for(i=0;i<256;++i)
if(letters[i]) data[j++] = letters[i];
if(j==1) {i=data[0];rate=8.0;} //注意只有一个字母的情况
else i = Haffman(data,j);
rate = Size*8.0/i;
cout<<Size*8<<' '<<i<<' '<<fixed<<setprecision(1)<<rate<<endl;
}
return 0;
}