1009

1009 Problem J

题意:对于一串字符,让使用频率高的二进制表示尽可能小,最终使得表示这串字符的二进制数最少。

思路:对于英文字母的编码就是求最优树,哈夫曼树每次让权值最小的树结合,得到新的节点,再利用新得到的权值,去计算下一个最小权值,最终让所有权值结合成一棵树,即得到最优树,以此来编码。

感想:权值的记录,以及左右兄弟的组合是问题关键,处理好此处,问题自然可解。

#include<iostream>

#include<string.h>

#include<stdio.h>

#include<algorithm>

using namespace std;

struct str{

    int l,r,c;

}tree[64];

int f[60];

int k;

string s;

void hefuman(int n,int p){

     if(f[n]==0) return ;

     if(n<=26) k+=f[n]*p;

     else{

       hefuman(tree[n].l,++p);

       hefuman(tree[n].r,p);

     }

}

int main(){

   int i,j,left,right;

   while(cin>>s){

       if(s=="END") break;

       int len=s.length();

       for(i=0;i<=60;i++) tree[i].c=-1;

       memset(f,0,sizeof(f));

       for(i=0;i<len;i++){       //统计字符个数

           if(s[i]=='_') f[26]++;

           else  f[s[i]-'A']++;

       }

       int node=26;

       while(1){

           int min=1000;

           for(i=0;i<=node;i++){

                if(tree[i].c==-1){

                   if(min>f[i]&&f[i]){

                        min=f[i];

                        left=i;

                    }

                }

           }

           min=1000;

           for(j=0;j<=node;j++){

                if(tree[j].c==-1){

                   if(min>f[j]&&j!=left&&f[j]){

                        min=f[j];

                        right=j;

                    }

                }

           }

           if(min==1000) break;

           f[++node]=f[left]+f[right];

           tree[node].l=left;

           tree[node].r=right;

           tree[node].c=-1;

           tree[left].c=node;

           tree[right].c=node;

       }

       k=0;

       if(node==26)  k=len;

       else hefuman(node,0);

       len*=8;

       printf("%d %d %.1f\n",len,k,len*1.0/k);

    }

   return 0;

 

}

 

你可能感兴趣的:(1009)