uvalive 2088

题目连接:2088 - Entropy


题目大意:给出一个字符串, 包括A~Z和_, 现在要根据字符出现的频率为他们进行编码,要求编码后字节最小, 然后输出字符均为8字节表示时的总字节数, 以及最小的编码方式所需的总字节数,并输出两者的比率, 保留一位小数。


解题思路:huffman编码。


#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int N = 10005;

struct Node {
    int r;
    int l;
    int cnt;
    bool operator < (const Node& a) const {
        return cnt > a.cnt;
    }
}tmp[N];

int len, sum, vis[N];

void init(char str[]) {
    memset(tmp, 0, sizeof(tmp));
    memset(vis, 0, sizeof(vis));
    sum = 0;
    len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        if (str[i] == '_')
            vis[26]++;
        else
            vis[str[i] - 'A']++;
    }
}

void count(Node cur, int deep) {
    if (cur.l == -1 && cur.r == -1) {
        sum += deep * cur.cnt;
	return;
    }
    if (cur.l != -1)   
	count(tmp[cur.l], deep + 1);
    if (cur.r != -1)
	count(tmp[cur.r], deep + 1);
}

void solve() {
    int n = 0;
    Node now;
    priority_queue<Node> que;
    for (int i = 0; i < 27; i++)
	if (vis[i]) {
	    now.cnt = vis[i];
	    now.l = now.r = -1;
	    que.push(now);
	}

    while (1) {
	tmp[n++] = que.top(),    que.pop();
	if (que.empty())    break;
	tmp[n++] = que.top(),    que.pop();
	now.cnt = tmp[n - 1].cnt + tmp[n - 2].cnt;
	now.l = n - 1, now.r = n - 2;
	que.push(now);
    }
    if (n == 1)
	sum = tmp[n - 1].cnt;
    else
	count(tmp[n - 1], 0);
}

int main() {
    char str[N];
    while (scanf("%s", str) == 1) {
	if (strcmp(str, "END") == 0)	break;

	init(str);
	solve();
	printf("%d %d %.1lf
", len * 8, sum, len * 8.0 / sum);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/riskyer/p/3297022.html