合並果子(貪心)


題目:合並果子(貪心)

題意:

n堆果子,每次合並可以選擇任意兩堆合並,每次合並的消耗的體力是這兩堆果子的重量和,求把n堆果子合並成1堆所需消耗體力的最小值。

輸入格式

輸入包括兩行,第一行是一個整數 n,表示果子的種類數。

第二行包含 n 個整數,用空格分隔,第 i 個整數 ai 是第 i 種果子的數目。

輸出格式

輸出包括一行,這一行只包含一個整數,也就是最小的體力耗費值。

輸入數據保證這個值小於 2^31

數據范圍

1≤n≤10000,
1≤ai≤20000

輸入樣例:

3

1 2 9

輸出樣例:

15

樣例解釋:

第一次合並選擇1和2,消耗體力3,第二次合並選擇3和9,消耗體力12。總共消耗的體力為3 + 12 = 15。

題目分析:貪心。

解題步驟:

  1. 每次選擇序列中最小的兩個元素進行合並,序列中添加一個新的元素,即這兩個元素的和。
  2. 重復步驟1,直到序列中的元素為1個。

貪心策略證明:

如下圖,如果把合並的過程看成一棵樹,葉子節點為要合並的果子的數量。可以知道,越先合並的果子的深度越大,權重也會越大。例如下圖中,a和b在合並的時候會被加1次,(a + b)和c在合並的時候會被加1次,所以a加了兩次,b加了兩次,c加了一次。

  1. 設貪心得出的答案是cnt,本題的正確答案是ans。
  2. 由於本題的答案ans是所有合並方案的最小值,所以必有ans <= cnt。
  3. h(x)x在樹中的深度,設在正確答案中有c < ah(c) < h(a),則我們可以交換ac的合並順序,交換不影響其他點的權重。交換后,數值小的點權重變大,數值大的點權重變小,且a和c的權重改變量是相等的,所以交換后能夠得到更小的答案。故有cnt <= ans。
  4. 由於ans <= cntcnt <= ans,得cnt = ans。

                      

 

 

AC代碼:

#include<iostream>

#include<queue>

 

using namespace std;

 

void solve(){

    int n;

    scanf("%d", &n);

    

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

    while(n--){

        int x;

        scanf("%d", &x);

        pq.push(x);

    }

    

    int res = 0;

    while(pq.size() > 1){

        int x = pq.top(); pq.pop();

        int y = pq.top(); pq.pop();

        

        res += x + y;

        pq.push(x + y);

    }

    printf("%d\n", res);

}

 

int main(){

    solve();

    

    return 0;

}

時間復雜度:O(NlogN)。

空間復雜度:O(N)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM