05-樹9 Huffman Codes(不建樹)

原題鏈接

樹(下)課後練習題3

解題思路

題目給了提示,不一定要每次都建立哈夫曼樹,而是通過比較前綴碼的長度是否爲最優。

那麼對於給定的一組字符和頻率(因爲輸入輸出字符都是按順序的,所以沒必要存這些字符),可以不建哈夫曼樹的得到其WPL,主要是利用優先隊列模擬小頂堆,只要優先隊列中的元素個數大於1,就從中取出最小的兩個元素,WPL加上這兩個元素的和,然後再將這兩個元素的和入隊。

爲什麼是這樣的?來自於合併果子問題。
在這裏插入圖片描述
在這裏插入圖片描述

如何判斷一個同學的結果是否正確有兩個地方:

  1. 判斷其編碼的wpl是否等於最優WPL
    得到WPL後,針對每個同學的結果,在輸入時,記錄下來編碼(爲了判斷是否是前綴碼,無二義性的),然後計算該同學編碼結果的wpl,wpl每次都加上頻率*編碼長度。

  2. 判斷這些編碼是否是無二義性的前綴碼
    將編碼按字符串長度從小到大排序,然後依次看每一個編碼是否是後面編碼的一部分即可

源代碼

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100;
priority_queue<int, vector<int>, greater<int> > q;//優先隊列替代小頂堆
int data[maxn];//存放各個元素的頻率 
string prefix[maxn];//存放各個前綴 
int n, WPL = 0; 
bool cmp(string s1, string s2){
	return s1.length() < s2.length();
}
bool check(){
	char ch;
	int wpl = 0;
	bool flag = true;//答案是否正確 
	for(int i=0; i<n; i++){
		cin>>ch;
		cin>>prefix[i];
		wpl += data[i]*prefix[i].length();
	}
	if(wpl != WPL)
		flag = false;
	//下面繼續判斷是否爲前綴碼
	//按長度排序
	sort(prefix, prefix+n, cmp); 
	for(int i=0; i<n-1; i++){
		for(int j=i+1; j<n; j++){
			if(prefix[i] == prefix[j].substr(0, prefix[i].length())){
				flag = false;
				break;
			}
		} 
	}
	return flag;	 
}
int main(){
	int m;
	cin>>n;
	getchar();
	char ch;
	for(int i=0; i<n; i++){
		cin>>ch;
		cin>>data[i];
		getchar();
		q.push(data[i]);
	}
	//求出正確的WPL 
	while(q.size() > 1){
		int top1 = q.top();
		q.pop();
		int top2 = q.top();
		q.pop();
		WPL += (top1+top2);
		q.push(top1+top2); 
	}
//	printf("%d\n", WPL);
	cin>>m;
	for(int i=0; i<m; i++){
		if(check())//WPL是最短且是前綴碼 
			cout<<"Yes"<<endl;
		else
			cout<<"No"<<endl; 
	}
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章