HDU_1053 Entropy
这道题目的长度很吓人,其实就是一道很裸的Hufuman编码问题,一般的《数据结构》书上都有,不说了,上代码:
#include <stdio.h>
#include <string.h>
#define N 128
#define inf 0x7fffffff
struct node
{
int val; //权值
int left, right, parent;
}p[1000];
int f[N]; //存放每个字母权值
int len[N]; //统计编码的长度
void hufuman(int n)
{
int i, min1, min2, pos1, pos2, flag;
for(i =0; i < n; i++)
{
p[i].val = f[i];
p[i].parent =-1;
p[i].left =-1;
p[i].right =-1;
}
while(1) //构建Hufuman树
{
int mark1 =0, mark2 =0;
min1 = min2 = inf;
for(i =0; i < n; i++) //每次取最小和第二小的元素
{
if(p[i].parent ==-1&& p[i].val < min1)
{
if(min1 != min2)
{
min2 = min1;
pos2 = pos1;
mark2 =1;
}
min1 = p[i].val;
pos1 = i;
mark1 =1;
}
elseif(p[i].parent ==-1&& p[i].val < min2)
{
min2 = p[i].val;
pos2 = i;
mark2 =1;
}
}
if(mark1 ==0|| mark2 ==0) //如果没有则跳出,表示已经建好Hufuman树
break;
p[n].val = min1 + min2;
p[pos1].parent = n;
p[pos2].parent = n;
p[n].left = pos1;
p[n].right = pos2;
p[n].parent =-1;
n++;
}
for(i =0; i < n; i++)
{
if(p[i].right !=-1|| p[i].left !=-1) //如果不是原有的元素,而是后来构建出来的,则说明编码长度已经统计完
break;
flag = i;
len[i] =1;
while(p[flag].parent !=-1)
{
len[i]++; //统计编码长度(这地方没有必要得出Hufuman编码,这道题用不到)
flag = p[flag].parent; //跳到i的父节点,继续查找
}
}
return;
}
int main()
{
char str[N];
int data[N], i;
while(gets(str) != NULL)
{
if(!strcmp(str, "END")) break;
memset(data, 0, sizeof(data));
memset(f, 0, sizeof(f));
for(i =0; i < strlen(str); i++)
data[(int)str[i]]++; //求出每个字母的权值
int num =0;
for(i =0; i <128; i++)
{
if(data[i] !=0)
{
f[num++] = data[i]; //给每个字母编号num,并将权值存到f[]
}
}
if(num ==1)
{
printf("%d %d 8.0\n",strlen(str)*8, f[0]);
continue;
}
hufuman(num);
int sum =0;
for(i =0; i < num; i++)
{
if(len[i] !=1)
sum += (len[i]-1)*f[i]; //编码总长度 = sum(每个字母所对应的编码长度 * 字母出现的次数)
}
printf("%d %d %.1f\n", strlen(str)*8,sum, strlen(str)*8/(float)sum);
}
return0;
}