[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\n",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\n",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)\n",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\n",len*8,length,(double)(len*8)/length);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章