來源:https://www.luogu.com.cn/problem/UVA12676
題目大意:已知huffman編碼長度,反過來估計各葉子結點的最小權重和。
這裏面的隱含條件就是:
1)求各葉子節點的權重和 = 求huffman樹根節點的權重
2)(重點)上層葉子節點一定至少是下層各節點權重的最大值!(這也解決了如何讓葉子節點的權重和最小問題)
最重要的解題思路是:
從上而下推理,假設最深層權重假設全爲1(保證得到最小權重),下層節點合併,得到上層新生成的中間節點,而原有的上層的葉子節點等於是下層各節點權重的最大值,再繼續合併,直到合併爲最終的根節點。
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類型