• [POJ1521]Huffman编码


     [POJ1521]Huffman编码

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    输入一个字符串,长度不超过100,仅由大写字母和下划分组成。求用最好的字符编码方式,令总长度最小。

    输入

    多组数据,每组数据在一行上输入一个字符串,格式如前所述

    当遇到END时,表示输入结束

    输出

    对应每个输入,在一行上输出3个信息:首先是每个字母按固定长度8bit编码,字符串的总长度,然后是按最优编码的总长度,最后是前者对后者的比率,保留1位小数。

    样例输入

    AAAAABCD
    THE_CAT_IN_THE_HAT
    END
    

    样例输出

    64 13 4.9
    144 51 2.8




    这道题思路就是构造哈夫曼树,然后从根一遍dfs扫出叶节点深度(就

    是每个字符的编码长度)最后按照算出来的编码算原字符串的长度。


    哈夫曼编码:
    普通的unsigned char最大255 长度为2^8 二进制下长度8位
    传输时数据量较大。哈夫曼编码按照每个字符的出现频率为字符编出长
    1-8位(二进制)的编码,出现频率越高的字符编码越短,能有效缩减
    传输信息长度,而且不会出现歧义。


    哈夫曼树:
    哈夫曼树属于2×树。其中,每一个叶节点都代表一个字符,向左延伸
    的边代表‘0’,向右延伸的边代表1
    从根节点出发到叶节点的01路径就代表此叶节点字符的哈夫曼编码


    构造哈夫曼树:
    先生成出现字母的叶节点,吧节点的权重设为字母出现次数,压入大根
    优先队列,每次取出两个节点(权重最小),新建一个节点作为这两个
    节点的父亲(新节点不能表示什么,只起结构作用),新节点权重为儿
    子节点之和。把新节点压入优先队列。如此反复,到队列中只有一个节
    点时结束。此时队列中节点为根。


    最后从根节点dfs标记叶节点深度,深度就是0-1串编码长度。最后在扫
    原字符串累和即可。




    代码也不长,但是从昨天一直wa,一开始就想到字符串有只有一个相同
    字符的情况,随手就特判打了puts("8 1 8.0"); 然后接着wa,之后再
    网上找到正确代码对拍1000+组数据才发现我的程序被"QQ"终结了。
    才发现是特判错误,改成printf("%d %d 8.0 ",len*8,len)就AC了

        = =   这也算犯二吧

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    char str[120];
    int cnts[27];
    bool cmp(int a,int b){
        return cnts[a]<cnts[b];
    }
    int prs(char c){
        if(c>='A'&&c<='Z')c-='A'-1;
        else c=0;
        return c;
    }
    char unp(int i){
        if(i>=1)i+='A'-1;
        else i='_';
        return (char)i;
    }
    struct Node{
        int l,r;
        Node(){}
    }nodes[600];
    int tot=27;
    struct mpair{
        int a,b;
        mpair(){}
        mpair(int aa,int bb){a=aa,b=bb;}
        bool operator<(mpair an)const{
            return b>an.b;
        }
    };
    /*int fa[600];
    int root(int a){
        if(fa[a])return fa[a]=root(fa[a]);
        return a;
    }*/
    int lens[27];
    void dfs(int u,int depth){
        if(u<=26){lens[u]=depth;return;}
        else dfs(nodes[u].l,depth+1),dfs(nodes[u].r,depth+1);
    }
    void init(){
        tot=27;
        memset(nodes,0,sizeof nodes);
        memset(cnts,0,sizeof cnts);
        memset(lens,0,sizeof lens);
    }
    int main(){
        while(~scanf("%s",str)){
            if(!strcmp(str,"END"))return 0;
            init();
            int len=strlen(str);
            for(int i=0;i<len;i++)cnts[str[i]=prs(str[i])]++;
            priority_queue<mpair> que;
            int ecnt=0;
            for(int i=0;i<=26;i++)if(cnts[i])
                que.push(mpair(i,cnts[i])),ecnt++;
            if(ecnt==1){
                printf("%d %d 8.0
    ",len*8,len);
                continue;
            }
            while(ecnt>1){
                mpair a,b;
                a=que.top();
                que.pop();
                b=que.top();
                que.pop();
                //printf("union:%d(%d) %d(%d)
    ",a.a,a.b,b.a,b.b);
                nodes[tot].l=a.a;
                nodes[tot].r=b.a;
                que.push(mpair(tot++,a.b+b.b));
                ecnt--;
            }
            dfs(que.top().a,0);
            int length=0;
            for(int i=0;i<len;i++)length+=lens[str[i]];
            printf("%d %d %0.1lf
    ",len*8,length,(double)(len*8)/length);
        }
    }


  • 相关阅读:
    用户访问集群架构的流程
    HTTP请求方法 HTTP的响应方法
    数据报文
    什么是HTTP? 什么是超文本? 什么是URL?
    HTTP协议原理
    C语言之数据类型③——字符与字符串
    C语言之数据类型②——浮点类型
    C语言之数据类型①——整数类型
    uniapp自定义小程序左上角的图标并且添加自定义事件
    在uniapp中使用iconfont
  • 原文地址:https://www.cnblogs.com/Hineven/p/5843580.html
Copyright © 2020-2023  润新知