2-5 修理牧場 (35分) 哈夫曼樹例題 c與c++鴛鴦解法 詳細解釋

農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要N塊木頭,每塊木頭長度爲整數Li個長度單位,於是他購買了一條很長的、能鋸成N塊的木頭,即該木頭的長度是Li​​的總和。

但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。爲簡單起見,不妨就設酬金等於所鋸木頭的長度。例如,要將長度爲20的木頭鋸成長度爲8、7和5的三段,第一次鋸木頭花費20,將木頭鋸成12和8;第二次鋸木頭花費12,將長度爲12的木頭鋸成7和5,總花費爲32。如果第一次將木頭鋸成15和5,則第二次鋸木頭花費15,總花費爲35(大於32)。

請編寫程序幫助農夫計算將木頭鋸成N塊的最少花費。

輸入格式:

輸入首先給出正整數N(≤10000​​ ),表示要將木頭鋸成N塊。第二行給出N個正整數(≤50),表示每段木塊的長度。

輸出格式:

輸出一個整數,即將木頭鋸成N塊的最少花費。

輸入樣例:

8
4 5 1 2 1 3 1 1

輸出樣例:

49

思路

構造最優二叉樹,將除葉節點外所有的節點權值加和。即爲所求。

實際上是沒必要構造一顆樹的,運用他的原理即可

其實這兩個解法差不多,但是c++更加的簡單易於理解,在時間上也是很短的。c相對而言就比較暴力了。相當於對c++解法的底層解釋。注重基礎。

c++解法

#include<stdio.h>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > Q;
int main(){
    int x,n,sum = 0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&x);
        Q.push(x);
    }
    while(Q.size()>1){
        int a=Q.top();
        Q.pop();
        int b=Q.top();
        Q.pop();
        Q.push(a+b);
        sum+=a+b;
    }
    printf("%d",sum);
    return 0;
}

在這裏解釋一下這句話

priority_queue<int,vector<int>,greater<int> > Q;

priority_queue<Type, Container, Functional>,其中Type 爲數據類型,Container爲保存數據的容器,Functional 爲元素比較方式。
Container必須是用數組實現的容器,比如vector,deque等等,但不能用 list。STL裏面默認用的是vector。
greater 可以實現由底部到頂部大到小實現。
所以這道題的步驟就是,
push出兩個最小值並相加,將相加的值加到sum並放回Q中,然後會重新排列大小。
以此類推

在這裏插入圖片描述
不僅代碼量很少,時間也是很短的,考試的時候可以使用,平時練習不建議,有點投機取巧。練習還是用c一步步實現他的每一個步驟。

c解法

用c語言其實就是對c++的具體實現,(可能我這個不是最好的解法。)但是每次取每次放都需要重新排序,這將是一件很累的事情。所以乾脆就不排序了,直接放在那,取的時候再去判斷最小值。

#include <stdio.h>
int a[10010],n;
#define Max 10000000
int findMin(){
    int min = Max+1,i;
    for (i = 0; i<n; i++)
        if (min>a[i]) min = a[i];
    return min;
}
void Delete(int x){
    int i;
    for (i = 0; i<n; i++)
        if (a[i] == x) {
            a[i] = Max;
            return;
        }
}
void add(int x){
    int i;
    for (i = 0; i<n; i++)
        if (a[i] == Max) {
            a[i] = x;
            return;
        }
}
int main(){
    int i,sum2 = 0;
    scanf("%d",&n);
    for (i = 0; i<n; i++)
        scanf("%d",&a[i]);
    for (i = 1; i<n; i++) {
        int x = findMin();
        Delete(x);
        int y = findMin();
        Delete(y);
        add(x+y);
        sum2+=x+y;
    }
    printf("%d\n",sum2);
}

這裏註明一下:刪除其實就是把現在這個數組裏這個值(不一定是之前取的那個數)給賦值爲非常大,這樣下次尋找最小值就不會找到他。
如果有添加,那麼之前一定有刪除,直接把添加的值放在刪除的值的地方就行了。
Max一定要特別大,要不然,最大值測試用例時,x+y的值甚至會大過Max,這樣就出錯了。
這個實現就很耗時了,算是鍛鍊思維把。
在這裏插入圖片描述

如果有更好的解法,或者是有什麼問題的話,歡迎留言。

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