哈夫曼樹 荷馬史詩-洛谷
阿新 • • 發佈:2018-12-04
這道題目做了五個多小時,主要還是不瞭解哈夫曼樹的一些細節問題,自己做個總結吧。
題目連結:https://www.luogu.org/problemnew/show/P2168
總結:
一:這道題目的一些收穫
1:求最終編碼文字的長度,不一定必須讓字元組成的編碼的長度資訊必須儲存在葉子結點。可以在建立的時候,定義一個ans=0,在從下向上建立哈夫曼樹的時候,不斷的相加。比如,有個高度為h的結點,他的結點帶權路徑長度(不懂定義看二的概念),可以是h個w(權重)相加。這在建樹的過程中可以實現。本題目就是採用的這種方式
2:結點的選擇:選擇權值最小,並且高度較小的。(權值較小的可以理解,那麼高度較小呢?題目中說了,求的是最長字串 si 的最短長度,有兩個權值相同的結點,將h更大的結點,留到後面,會讓最長字串的最短長度更小)當時自己就是錯在這裡,火來參考了大神的程式碼
3:***新增空結點
當時多進位制的時候。因為每次都是將k個節點合併為1個(減少k-1個),一共要將n個節點合併為1個,如果(n-1)%(k-1)!=0 則最後一次合併時不足k個。也就表明了最靠近根節點的位置反而沒有被排滿,因此我們需要加入k-1-(n-1)%(k-1)個空節點使每次合併都夠k個節點(也就是利用空節點將其餘的節點擠到更優的位置上)。
二:一些概念
- 結點帶權路徑長度:L*W(W是這個結點的權值,L是這個結點的深度,根節點的深度是0)。
- 樹的帶權路徑長度:所有葉子結點的結點帶去按路徑長度之和。
三:思想:
自底向上,每次選擇最小的兩個結點,合成一個結點。
四:特點:
- 不存在度為1的結點
- n個結點的哈夫曼樹總共需要結點2n-1,所以對於二進位制的編碼,開的空間最小是2n-1。
- 順序儲存,存在結構體裡面挺好。
#include <bits/stdc++.h> using namespace std; #define ll long long struct Node{ ll cnt,h; Node(ll CNT,ll H){ cnt=CNT,h=H; } }; bool operator<(const Node a,const Node b){ if(a.cnt!=b.cnt) return a.cnt>b.cnt; else return a.h>b.h; } priority_queue<Node> q; int main() { int n,len,i,j; cin>>n>>len; for(i=0;i<n;i++){ ll temp; scanf("%lld",&temp); q.push(Node(temp,1)); } if(0!=((n-1)%(len-1))){ int add=len-1-(n-1)%(len-1); for(i=0;i<add;i++) q.push(Node(0,1)); n+=add; } ll ans=0; while(q.size()>1) { ll sum=0,maxh=0; for(i=0;i<len;i++){ maxh=max(q.top().h,maxh); sum+=q.top().cnt; q.pop(); } ans+=sum; q.push(Node(sum,maxh+1)); } printf("%lld\n%lld",ans,q.top().h-1); return 0; }