石子合併,GarsiaWachs演算法優化

2022-05-29 20:39:09 字數 1636 閱讀 5574

思路:可以發現樸素的區間dp已經不足以解決這個問題了。對於石子合併問題,有乙個最好的演算法,那就是garsiawachs演算法。時間複雜度為o(n^2)。

設序列是stone[maxn],從左往右,找到乙個最小的且滿足stone[k-1] <= stone[k+1]的k,找到後合併stone[k]和stone[k-1],再從當前位置開始向左找乙個j滿足stone[j] >= stone[k]+stone[k-1],然後把stone[k]+stone[k-1]插到j的後面就行。一直重複,直到只剩下一堆石子就可以了。

另外在這個過程中,可以假設stone[-1]和stone[n]是正無窮的,可省略邊界的判別。把stone[0]設為inf, stone[n+1]設為inf-1,可實現剩餘一堆石子時自動結束。

舉個例子:

186 64 35 32 103

因為35<103,所以最小的k是3(下標從0開始),我們先把35和32刪除,得到他們的和67,並向前尋找乙個第乙個大於等於67的數,把67插入到他後面,得到:186 67 64 103,現在由5個數變為4個數了,繼續:186 131 103,之後得到234 186,k=2(別忘了,設a[-1]和a[n]等於正無窮大),最後得到420。最後的答案呢?就是各次合併的重量之和,即420+234+131+67=852。

基本思想是通過樹的最優性得到乙個節點間深度的約束,之後證明操作一次之後的解可以和原來的解一一對應,並保證節點移動之後他所在的深度不會改變。具體實現這個演算法需要一點技巧,精髓在於不停快速尋找最小的k,即維護乙個「2-遞減序列」樸素的實現的時間複雜度是o(n*n),但可以用乙個平衡樹來優化,使得最終複雜度為o(nlogn)。

ac_code

#include #include 

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;const

int maxn=50005

;const ll mod=1e9+7

;const

int inf=0x3f3f3f3f

;const

double eps = 1e-9

;int

stone[maxn],n,ans,t;

void combine(int

k) stone[j]=tmp;

while( j>=2 && stone[j]>=stone[j-2

] )}

intmain()

ans=0

; t=3

;

for(int i=3;i<=n+1;i++)

}while( t>3 ) combine(t-1

); printf(

"%d\n

",ans);

}return0;

}

石子合併 GarsiaWachs演算法

對於石子合併問題,有乙個最好的演算法,那就是garsiawachs演算法。時間複雜度為o n 2 它的步驟如下 設序列是stone 從左往右,找乙個滿足 stone k 1 stone k 1 的k 找到後合併 stone k 和stone k 1 再從當前位置開始向左找最大的 j,使其滿足 sto...

石子合併問題

在乙個圓形操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。分析 假設有n堆石子需要合併,可以設計乙個2 n 1個元素的陣列來儲存每堆石子的個數。...

石子合併問題

在乙個圓形操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。沒有用dp 感覺一般的也能寫,時間複雜度也不高。include include inc...