Problem Description

文本编码是计算机通信中的常见问题。

以文本“AAAAABCD”为例,如果使用ASCII,则一共需要64位(因为每个字符的ASCII编码都是需要8位)。

对应的,如果我们将A编码为“00”,“B”为“01”,“C”为“10”,“D”为“11”,那么我们可以只编码16位; 得到的位模式将是“0000000000011011”。然而,这仍然是一种固定长度的编码。

由于字符“A”的出现频率较高,我们是否可以通过用较少的位对它进行编码来获得更好的效果?

事实上,我们确实可以。

最佳编码是将“A”标记为“0”,“B”标记为“10”,“C”标记为“110”,“D”标记为“111”。(显然,这不是唯一的最佳编码,因为很显然,对B,C和D可以自由交换,而不增加最终编码的大小。)

使用这种编码,上述的字符串仅需要13位,编码为“0000010110111”,相对ASCII编码方案,压缩比为4.9比1。通过从左到右读取该编码,您会发现,无前缀编码可以很容易地将其解码为原始文本,即使代码具有不同的位长度。

Input
输入包含多组文本字符串,每行一个。
文本字符串将只包含大写字母、数字字符和下划线(用于代替空格)。
单词“END”表示输入结束,不做处理。

Output
对于输入中的每个文本字符串,输出8位ASCII编码的长度、最佳编码的长度,以及对应的压缩率比值,压缩比精确到小数点后一位。


输入样例

AAAAABCD
THE_CAT_IN_THE_HAT
END
 

输出样例

64 13 4.9
144 51 2.8
附ac代码
#include<iostream>
#include<cstdio>
#include<cstring> 
#include<queue>
#include<cmath>
using namespace std;
int ch[40];
int bfs()
{
    int a,b;
    int ans=0;
    priority_queue<int,vector<int>,greater<int> >qu;//实现小顶堆 优先队列默认大顶堆
    //注意int的尖括号和queue的尖括号之间要有空格 
    for(int i=0;i<=37;++i)
    {
        if(ch[i]) qu.push(ch[i]); 
        //哈夫曼编码的编码长度与树的深度相同故求总长即求树的带权路径 
    }
    if(qu.size()==1)
    ans=qu.top();
    //哈夫曼编码若结点大于1一定时完全二叉树
    while(qu.size()>1)
    {
        a=qu.top();
        qu.pop();
        b=qu.top();
        qu.pop();
        ans+=(a+b);
        qu.push(a+b); 
     }
    return ans; 
}
int main()
{
    string str;
    while(cin>>str)
    {
        if(str[0]=='E'&&str[1]=='N'&&str[2]=='D'&&str.size()==3)
        break;
        memset(ch,0,sizeof(ch));
        for(int i=0;i<str.size();++i)
        {
            if(str[i]=='_')
            ch[26]++;
            else
            {
                if(str[i]>='A'&&str[i]<='Z')
                ch[str[i]-'A']++;
                else
                ch[str[i]-'0'+28]++;
            }
        }
        int ans1=str.size()*8,ans2=bfs();
        double ans3=round(((double)ans1/ans2)*10)/10;
        printf("%d %d %.1lf\n",ans1,ans2,ans3);
    }
    return 0;
}

 

 
 posted on 2022-12-01 23:31  ruoye123456  阅读(242)  评论(0编辑  收藏  举报