題目描述
在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。
每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過n-1次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所消耗體力之和。
因為還要花大力氣把這些果子搬回家,所以多多在合併果子時要盡可能地節省體力。假定每個果子重量都為1,並且已知果子的種類數和每種果子的數目,你的任務是設計出合併的次序方案,使多多耗費的體力最少,並輸出這個最小的體力耗費值。
例如有3種果子,數目依次為1,2,9。可以先將1、2堆合併,新堆數目為3,耗費體力為3。接著,將新堆與原先的第三堆合併,又得到新的堆,數目為12,耗費體力為12。所以多多總共耗費體力=3+12=15。可以證明15為最小的體力耗費值。
輸入
第一行是乙個整數n(1<=n<=10000),表示果子的種類數。第二行包含n個整數,用空格分隔,第i個ai(1<=ai<=20000)是第i個果子的數目。輸出
輸出包括一行,這一行只包含乙個整數,也就是最小的體力耗費值。輸入資料保證這個值小於2^31。樣例
輸入
31 2 9
輸出15
提示
該題目用堆做,寫刪除函式時較為複雜,所以可以考慮優先佇列。
普通的佇列是一種先進先出的資料結構,元素在佇列尾追加,而從佇列頭刪除。
在優先佇列中,元素被賦予優先順序。當訪問元素時,具有最高優先順序的元素最先刪除。優先佇列具有最高端先出 (first in, largest out)的行為特徵。
優先佇列具有佇列的所有特性,包括佇列的基本操作,只是在這基礎上新增了內部的乙個排序,它本質是乙個堆實現的。
下面是優先佇列的使用方法
首先要包含標頭檔案
#include
```和佇列基本操作相同:
top(
) 訪問隊頭元素
empty
() 佇列是否為空
size
() 返回佇列內元素個數
push
() 插入元素到隊尾 (並排序)
emplace
() 原地構造乙個元素並插入佇列
pop(
) 彈出隊頭元素
swap (
)交換內容
priority_queue<
int,vector<
int>
,greater<
int>
> q;
//定義小頂堆
priority_queue<
int,vector<
int>
,less<
int>
> q;
//定義大頂堆
priority_queue<
int>
//預設為定義的大頂堆
//greater和less是std實現的兩個仿函式(就是使乙個類的使用看上去像乙個函式。其實現就是類中實現乙個operator(),這個類就有了類似函式的行為,就是乙個仿函式類了)
下面是這道題用優先佇列的解法
#include
#include
using
namespace std;
const
int n=
100001
;int m=
0x3f3f3f3f
;int top[n]
;priority_queue<
int,vector<
int>
,greater<
int>
> q;
intmain()
int ans=0;
for(i=
0;i1;i++
) cout
}
樹 堆結構練習 合併果子之哈夫曼樹
在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過n 1次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所消耗體力之和...
樹 堆結構練習 合併果子之哈夫曼樹
time limit 1000ms memory limit 65536k 有疑問?點這裡 在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經...
樹 堆結構練習 合併果子之哈夫曼樹
樹 堆結構練習 合併果子之哈夫曼樹 time limit 1000ms memory limit 65536k 在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可...