對於合併果子一題方法的研究。

2021-07-11 19:57:28 字數 1130 閱讀 1230

noip2023年提高組——合併果子這道題目,還是比較水的,用一般的方法都能過,但是如果資料大一點的話就不太好辦了。

先說最普通的方法:

貪心+快排

也就是每做完一次貪心就快排然後取前兩個的最小值繼續貪心,這樣子下去最終可以得到最優解,但這樣效率不高,(對於提高組那題的資料能勉強卡過)所以我要介紹一種優先佇列的演算法:

優先佇列演算法是:

設que佇列表示原來的果子數目,quenow表示現在合併成一堆的果子數目,然後x,y分別表示這兩個佇列的隊首。

我們現在對於n堆石子我們需要合併n-1次,而合併第i次時的最優值quenow[i]就等於

min這三個分別表示當前合併第i次的時候:

合併原來x,x+1堆。

合併x堆並且合併已經合併過的第y堆。

合併已經合併過的第y堆和已經合併過的第y+1堆。

當第i次合併的最優值選項是第乙個的時候我們需要把x+2,第二個的時候我們需要把x+1,y+1,第三個時候則把y+2,這樣子才能得到下次計算的值——稱為更新隊首。

當然que和quenow的初始值為

quenow[i]=∞

que[i]

que[n+1]..que[∞]=∞

然後我們可以得知此演算法的時間複雜度應該是o(nlogn+n)

當然還有與其時間複雜度差不多的堆排序演算法也可行。

堆排序的演算法如下:

先對乙個序列a[1..n]建堆,由題目的要求可知,我們要建的堆為最小堆。然後我們把a[1]也就是這個堆的最小元素記錄下來,然後把a[1]與a[n]調換,並把當前a[1..n-1]變成最大堆(此過程為min_heapify(1)——表示把以1為根的子堆滿足最小堆性質),最後再把當前的a[1]加上調換前的a[1],然後把x累加a[1],再以此類推,最後的x則是最優解。(注意在乙個調換裡應有兩次min_heapify過程才能保證當前的最小堆性質,因為a[1]的值在中途改變過一次,要在呼叫一次來保證)

這是堆排序的方法,但是為什麼這道題用堆排序更快,而不用快速排序呢?原因是因為對於當前乙個堆,新加入的乙個元素只會使得乙個根的子女不滿足最小堆性質,其他的根的子女在過程中都不會受影響,因此這個min_heapify的效率最低為o(lgn)——o(h)。

然後因為要調換n次,所以整個程式的效率為o(nlgn),遠高於快排效率的o(nnlgn)。

每日一題 46 合併果子

思路在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過 n 1 次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所耗體...

每日一題 合併集合

一共有 n 個數,編號是 1 n,最開始每個數各自在乙個集合中。現在要進行 m 個操作,操作共有兩種 m a b,將編號為 a 和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作 q a b,詢問編號為 a 和 b 的兩個數是否在同乙個集合中 輸入格式 第一行輸入整數 n ...

合併果子 單調佇列的模板題

題目描述 在乙個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過n 1次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所耗...