【作題筆記】P1090 合併果子

題目大意:給定 \(n\) 個數,每次能夠任意選兩個數 \(a_i,a_j\) 相加,把相加的結果做爲一個新數繼續執行此操做,直到只剩一個數爲止。現要求使最後得出的這個數最小。ios

一個顯然的貪心策略:每次選最小的兩個數相加,獲得一個新數,而後繼續。可是,若是按照這樣的思路,那麼每次獲得新數後這個序列的單調性就有可能會被破壞。數組

如何解決呢?很顯然的一種方法,將新數加入序列後,再把這個序列排序。然而這樣作彷佛會超時。C++ STL 中提供了一種巧妙地解決方法:\(\mathtt{priority\_queue}\)。它地本質是建一個二叉堆,而後每當插入一個數,就維護這個二叉堆。那麼顯然,在這個題中,咱們須要建一個小根堆,使較小的元素老是先被取出進行操做。less

而後須要解決一個問題:spa

如何創建小根堆(使用\(\mathtt{priority\_queue}\))?code

這樣:priority_queue<int,vector<int>,greater<int> >q;。其中第一個 int 表明小根堆中存儲的數據類型, vector<int> 表明存儲的方式(vector 就是數組), greater<int> 就是從小到大(即小根堆)。而後大根堆的話就是 priority_queue<int,vector<int>,less<int> >q;排序

因而,作法就呼之欲出了:沒讀入一個數字,就插入小根堆中。而後,當元素個數大於等於 2 時循環,每次取出隊首的兩個元素相加,答案加上這個數字,再令新數入隊便可。隊列

請注意:這裏爲何循環條件時元素個數大於等於 2而不是 隊列不爲空 呢?用兔隊的一句話來回答:it

捕獲.PNG

參考代碼:io

#include <iostream>
#include <stdio.h>
#include <queue>

using namespace std;

int n,w;
priority_queue<int,vector<int>,greater<int> >q;

int main()
{
    long long ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){scanf("%d",&w);q.push(w);}
    while(q.size()>=2)
    {
        int x=q.top();q.pop();
        int y=q.top();q.pop();
        x+=y;
        ans+=x;
        q.push(x);
    }
    printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索