一、哈夫曼樹
1. 哈夫曼樹也稱最優二叉樹。
葉子節點的權值是對葉子節點賦予的一個有意義的數值量。
設二叉樹具有 n 個帶權值的葉子結點,從根節點到各個葉子結點的路徑長度與相應葉子結點權值的乘積之和叫做二叉樹的帶權路徑長度。
給定一組具有確定權值的葉子結點,可以構造處不同的二叉樹,將其中帶權路徑長度最小的二叉樹稱為哈夫曼樹。
2. 基本思想:
- 初始化:由給定的 n 個權值 $\left\{ \omega_{1},\omega_{2},\cdots ,\omega_{n}\right\}$構造 n 棵只有一個根節點的二叉樹,從而得到一個二叉樹集合$F=\left\{T_{1},T_{2},\cdots,T_{n}\right\}$。
- 選取與合並:在$F$中選取根節點的權值最小的兩顆二叉樹分別作為左右子樹構造一棵新的二叉樹(一般情況下將權值大的結點作為右子樹。),這棵新二叉樹的根節點的權值為其左、右子樹根節點的權值之和。
- 刪除與加入:在$F$中刪除作為左、右子樹的兩棵二叉樹,並將新建立的二叉樹加入到$F$中。
- 重復上述兩個步驟,當集合$F$中只剩下一棵二叉樹時,這棵二叉樹便是哈夫曼樹。
由哈夫曼算法構造的哈夫曼樹中,非葉子節點的度均為2。具有 n 個葉子結點的哈夫曼樹公有 2n-1個結點,其中有 n-1 個非葉子結點。它們是在 n-1 次的合並過程中生產的。
二、哈夫曼編碼
1. 哈夫曼編碼是一種可變字長編碼
如果一組編碼中任一編碼都不是其他任何一個編碼的前綴,我們稱這組編碼為前綴編碼。哈夫曼樹可用於構造最短的不等長編碼方案。
2. 算法流程
規定哈夫曼編碼樹的作分支代表 0,右分支代表 1,則從根結點到每個葉子結點所經過的路徑組成的 0 和 1 的序列便成為該葉子結點對應字符的編碼。
解碼則是將編碼串從左到右逐位判別,直到確定一個字符。
哈夫曼編碼樹中,樹的帶權路徑長度的含義是各個字符的碼長與其出現次數的乘積之和,所以采用哈夫曼樹構造的編碼是一種能使字符串的編碼總長度最短的不等長編碼。
三、題目:
1. POJ 3253
Description
Farmer John wants to repair a small length of the fence around the pasture. He measures the fence and finds that he needs N (1 ≤ N ≤ 20,000) planks of wood, each having some integer length Li (1 ≤ Li ≤ 50,000) units. He then purchases a single long board just long enough to saw into the N planks (i.e., whose length is the sum of the lengths Li). FJ is ignoring the "kerf", the extra length lost to sawdust when a sawcut is made; you should ignore it, too.
FJ sadly realizes that he doesn't own a saw with which to cut the wood, so he mosies over to Farmer Don's Farm with this long board and politely asks if he may borrow a saw.
Farmer Don, a closet capitalist, doesn't lend FJ a saw but instead offers to charge Farmer John for each of the N-1 cuts in the plank. The charge to cut a piece of wood is exactly equal to its length. Cutting a plank of length 21 costs 21 cents.
Farmer Don then lets Farmer John decide the order and locations to cut the plank. Help Farmer John determine the minimum amount of money he can spend to create the N planks. FJ knows that he can cut the board in various different orders which will result in different charges since the resulting intermediate planks are of different lengths.
Input
Lines 2.. N+1: Each line contains a single integer describing the length of a needed plank
Output
Sample Input
3 8 5 8
Sample Output
34
Hint
The original board measures 8+5+8=21. The first cut will cost 21, and should be used to cut the board into pieces measuring 13 and 8. The second cut will cost 13, and should be used to cut the 13 into 8 and 5. This would cost 21+13=34. If the 21 was cut into 16 and 5 instead, the second cut would cost 16 for a total of 37 (which is more than 34).
由題意可知對數據構造Huffman樹,其中非葉子節點的值加起來的和為所求。這里無需真正構造哈夫曼樹,哈夫曼樹的構造過程是不斷選擇集合種兩個權值最小的結點,然后刪除此兩結點,加入新的權值。利用最小堆即可。
1 #include <iostream> 2 #include <queue> 3 4 using namespace std; 5 6 int main() 7 { 8 priority_queue<int ,vector<int>,greater<int> > q; 9 int n; 10 int num; 11 cin >> n; 12 while(n--) 13 { 14 cin >> num; 15 q.push(num); 16 } 17 18 long long sum = 0; 19 20 while(!q.empty()) 21 { 22 int num1 = q.top(); 23 q.pop(); 24 int num2 = q.top(); 25 q.pop(); 26 sum += num1 + num2; 27 if(q.empty()) 28 break; 29 q.push(num1 + num2); 30 } 31 32 cout << sum << endl; 33 return 0; 34 }