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次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所耗...