洛谷-UVA12676 Inverting Huffman(反轉樹)

來源:https://www.luogu.com.cn/problem/UVA12676

題目大意:已知huffman編碼長度,反過來估計各葉子結點的最小權重和。

這裏面的隱含條件就是:
1)求各葉子節點的權重和 = 求huffman樹根節點的權重
2)
(重點)上層葉子節點一定至少是下層各節點權重的最大值!(這也解決了如何讓葉子節點的權重和最小問題)

最重要的解題思路是:

從上而下推理,假設最深層權重假設全爲1(保證得到最小權重),下層節點合併,得到上層新生成的中間節點,而原有的上層的葉子節點等於是下層各節點權重的最大值,再繼續合併,直到合併爲最終的根節點。

輸入:
輸入文件包含多個測試用例,每個測試用例如下所述:
第一行包含一個整數 N2≤N≤50),表示文本中出現的不同字符數。
第二行包含 N 個整數 Li1≤Li≤50i=1,2,,N,表示由 huffman 算法生成的不同字符 的編碼長度。
假設至少存在一棵上述算法構建的樹,可以生成具有給定長度的編碼。
輸出:
對每個測試用例,輸出一行,表示所有字符總數的最小值。
 
舉例:
 
輸入:
4
3 1 2 3
 
輸出:
5
 

 

#include <bits/stdc++.h>
using namespace std;
vector<int> deep[100]; //已知條件是知道編碼長度,則就是知道了該節點的深度,同一深度可能有多次合併。 
int main(){
	int n;
	cin>>n;
	int maxDeep=0; 
	for(int i=0;i<n;i++){
		int m;
		cin>>m; //編碼長度 等於 節點深度 
		deep[m].push_back(0);//用0佔位 
		
		//跟新並記錄最大層數 
		if(m>maxDeep){
			maxDeep=m;
		} 
	}
	
	//假設葉子節點的權重(初值爲1,因爲最深層權重最小爲1)
	int temp=1;
	
	//深度爲m,則需要m-1次合併,自下而上 
	for(int i=maxDeep;i>0;i--){
		for(int j=0;j<deep[i].size();j++){
			if(deep[i][j]==0){//如果等於0 就代表是葉子節點 
				deep[i][j]=temp;//將葉子節點假設爲上一層節點的最大權重 
			}					
		}
		sort(deep[i].begin(),deep[i].end());//第i層從小到大排序,原因:獲得該層節點的最大的權值 
		//合併
		for(int j=0;j<deep[i].size();j=j+2){
			deep[i-1].push_back(deep[i][j]+deep[i][j+1]);//新生成的雙親節點(反向生成中間節點) 
			temp=deep[i][deep[i].size()-1];//保存該層節點的最大權值 
		}
	}
	cout<<*deep[0].begin()<<endl;
	return 0;
}

注意:權值可能很大,數組可定義爲long long類型

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章