1. 程式人生 > >Greedy——HDUOJ 1553 - Entropy(哈夫曼樹求解)

Greedy——HDUOJ 1553 - Entropy(哈夫曼樹求解)

原題

  • Problem Description

    哈夫曼解釋……..(內容過多)

  • Sample Input

    AAAAABCD
    THE_CAT_IN_THE_HAT
    END

  • Sample Output

    64 13 4.9
    144 51 2.8

解題思路:

這裡寫圖片描述

首先,得理解哈夫曼樹的原理和使用的價值。。。。

題目大概意思就是:
怎麼通過演算法讓字串儲存的空間大幅度的減少。

貪心:

一般一個字元用8bit儲存,所以一個字串(10個字元)就得80位的儲存空間。
通過哈夫曼樹

:用01二進位制去表示每一個字元,對於出現頻率多的字元則01數量少,對於出現頻率少的則01數量就多了。
構建完後,如上圖2-1(c)所示,對於C字元,出現的次數是5(也就是說需要用到5次C,可以理解為M到C需要經過5次,即T->M->C需要經過5次,因為C表示’10’(B),所以一共有5個’10’來儲存C,即10bit)
可以把所有非葉子節點的權值加起來,就是所有字元需要儲存的空間。
用哈夫曼樹演算法構建成數的種類有很多種,但總結果都是相同的。

程式碼:

#include <iostream>
#include <string>
#include <queue>
#include <functional> using namespace std; int main() { string test; int letterNum[27], sum; priority_queue<int, vector<int>, greater<>> HuffmanTree;//優先佇列,每次輸出堆頂(小頂堆) while (cin >> test) { if (!test.compare("END")) break; while
(!HuffmanTree.empty())HuffmanTree.pop(); memset(letterNum, 0, sizeof(letterNum)); sum = 0; for (const char&t : test)//計算每個字母出現的次數 { if (t == '_')letterNum[26]++;//空格用_表示 else letterNum[t - 'A']++; } for (const int&t : letterNum)//將每個字母出現的次數存入堆中 if (t != 0)HuffmanTree.emplace(t); if (HuffmanTree.size() == 1)sum = test.size();//如果只有一種字母,則字串長度就是該字串的儲存空間 while (HuffmanTree.size() > 1) { int temp = 0; for (int i = 0; i < 2; i++)//構建哈夫曼樹 {//每次都將最小的兩個數提取出來構建 temp += HuffmanTree.top(); HuffmanTree.pop(); } sum += temp; HuffmanTree.emplace(temp); } printf("%d %d %.1f\n", test.size() * 8, sum, test.size() * 8.0 / sum); } }