環形結構上的石子合併

2021-10-05 20:59:27 字數 1783 閱讀 2244

題目:

在乙個圓形操場的四周擺放 n 堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。

試設計出乙個演算法,計算出將 n堆石子合併成 1堆的最大得分。

輸入格式

資料的第 1行是正整數 n,表示有 n 堆石子。

第 2行有 n 個整數,第 i 個整數 ai​ 表示第 i 堆石子的個數。

輸出格式

1 行為最大得分

輸入樣例

713 7 8 16 21 4 18

輸出樣例

376演算法思想:

環形結構上的動態規劃問題

在許多環形結構的問題中,我們都能夠通過列舉法,選擇乙個位置把環斷開,變成

線性結構進行計算,最後根據每次列舉的結果求出答案。我們把能通過上述列舉方式求解環形問題稱為「可拆解的環形問題」,這也是本文章的主要研究物件。我們的目標是採取適當的策略避免列舉,從而使時間複雜度得到降低。

第一種策略:

執行兩側dp,第一次在任意位置把環斷開成鏈,按照線性問題求解;第二次通過適當的條件和賦值,保證計算出的狀態等價於斷開位置強制相連。

第二種策略:在任意位置斷開成鏈,然後複製一倍接在末尾。這是解決環形結構dp常用手法。

假設石頭為a1,a2,a3…an,首尾相連之後就是 a1,a2,a3…an,a1,a2,a3…an;序列長度變為原來的2倍。

a1,a2,a3…an,a1,a2,a3…an;

這樣和原來的線性石子合併一樣了,列舉區間長度2<= len<=n,列舉區間起點,這個有點區別,列舉範圍是1<= i <=2n

dp[ i ][ j ]=max(dp[ i ][ j ],dp[ i ][ k ]+dp[k+1][ j ]+(sum[ j ]-sum[ i-1 ]));

求區間終點 int j=i+len-1; if(j>n*2) break ; 越界結束

然後列舉環裝中的每乙個數為起點,長度為n的區間,求最大值即可。

for(int i=1;i<=n;i++)//列舉環狀序列的起點,長度為n

max=max(dp[i][i+n-1],max);//求最大值

完整**:

#include

using

namespace std;

const

int maxn=

450;

//區間長度為2*n

int dp[maxn]

[maxn]

;int sum[maxn]

;//字首和陣列

int a[maxn]

;//每堆石子的個數

intmain()

int in=1;

//首尾相連之後

for(

int i=n+

1;i<=

2*n;i++

) sum[i]+=

(sum[i-1]

+a[in++])

;for

(int len=

2;len<=n;len++

)//列舉區間長度}}

int max=-1

;for

(int i=

1;i<=n;i++

)//列舉環狀序列的起點,長度為n

max=

max(dp[i]

[i+n-1]

,max)

;//求最大值

printf

("%d\n"

,max);}

return0;

}

環形石子合併問題

環形石子合併問題是在普通的相鄰石子合併問題的基礎上稍加拓展,石子變成了環形的,也就是說每個石子都可能和其左右兩邊的石子合併。那麼它的dp解法也是基於普通的相鄰石子合併問題,不了解的同學可以參考我寫過的這篇文章。有兩種解法,但他們基本的演算法思想是一樣的。第一種是和上面鏈結文章的寫法類似,不同的是對於...

環形區間DP 環形石子合併

在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入輸出格式 輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行...

石子合併 動態規劃(環形)

1 問題描述 問題 nwpu noj 1148 在乙個圓形操場的四周擺放著n堆石子 n 100 現要將石子有次序地合併成一堆。規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,讀入石子堆數n及每堆的石子數 20 選擇一種合併石子的方案,使得做n 1次合併,...