1. 程式人生 > 其它 >Spring系列之手寫自定義的@Enable*註解

Spring系列之手寫自定義的@Enable*註解

技術標籤:資料結構與演算法

基本概念

問題:給定n個權值,作為n個葉結點,構造一棵二叉樹,而這棵樹的特點是,有n個葉節點,葉節點的值為給定的權值。而內部節點的值為子樹的權值和

帶權路徑:WPL = \sum depth*weight

哈夫曼樹是這種二叉樹中帶權路徑最小的

構造方法

設有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;
}