Spring系列之手寫自定義的@Enable*註解
阿新 • • 發佈:2021-01-21
技術標籤:資料結構與演算法
基本概念
問題:給定n個權值,作為n個葉結點,構造一棵二叉樹,而這棵樹的特點是,有n個葉節點,葉節點的值為給定的權值。而內部節點的值為子樹的權值和
帶權路徑:
哈夫曼樹是這種二叉樹中帶權路徑最小的
構造方法
設有n個權值,W={W1,W2,...Wn},各自構成一個根為自己的二叉樹
選擇權值最小的兩個Wi,Wj,從W中刪除Wi和Wj,合併為一棵根為Wi+Wj的二叉樹,加入W,即W=W-{Wi,Wj}+{Wi+Wj}
當只剩下一個的時候,結束,剩下的那個二叉樹,就是哈夫曼樹
證明
引理:假設W1和W2是最小的兩個權值,則他們一定是深度最深的分支節點的孩子
證明:假設不是W1和W2,而是Wx和Wy,設W1和W2的深度為p(或者p1和p2),Wx和Wy的深度為q,顯然p<=q,且W1,W2<=Wx,Wy
WPL1=X+p*(W1+W2)+q*(Wx+Wy) (X是除了這4個節點以外的帶權路徑)
交換W1和Wx,W2和Wy
WPL2=X+q*(W1+W2)+p*(Wx+Wy)
WPL1-WPL2=(p-q)(W1+W2)-(p-q)*(Wx+Wy)=(p-q)*(W1+W2-Wx-Wy)>=0
即交換後更小,矛盾
得證
接著用歸納法證明這個演算法成立:
n=2時顯然成立
假設n=k時成立
當n=k+1時,根據引理,將最小的兩個權值W1+W2合併成W1+W2,那這時候問題就轉化成n=k時的情況,所以成立
程式碼
poj3253
其實就是搞個小根堆,然後每次彈兩個最小的,加一下,放回去
#include<iostream> #include<queue> using namespace std; int main(){ typedef long long int LL; priority_queue<LL,vector<int>,greater<LL> > q; int n; scanf("%d",&n); while(n--){ LL t; scanf("%lld",&t); q.push(t); } LL ans=0; while(q.size()>1){ LL x=q.top(); q.pop(); LL y=q.top(); q.pop(); ans+=x+y; q.push(x+y); } printf("%lld\n",ans); return 0; }