區間dp P1880環狀石子合併題解

2021-09-26 10:25:46 字數 1500 閱讀 5562

傳送門

題目描述

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

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

輸入格式

資料的第1行試正整數n,1≤n≤100,表示有n堆石子.第2行有n個數,分別表示每堆石子的個數.

輸出格式

輸出共2行,第1行為最小得分,第2行為最大得分.

輸入輸出樣例

輸入 #1 複製

44 5 9 4

輸出 #1 複製

4354

##題解##

1.題目要求求區間內的最大值以及最小值,很明顯就需要通過子區間的狀態傳遞來實現動規操作了。

2.本題有乙個很重要的點。就是該資料是呈環狀的。

也就是說我們dp得到的答案是這樣的: dp[i][i+n-1]。且1<=i<=n。而並不是一般dp的:dp[1][n];

那這個問題怎麼解決呢?goodquestion。直接將我們的dp邊界擴大一倍。

拆環成鏈。

3.dp方程其實很簡單。

在我們的區間i,j中列舉乙個k來求得最小/最大值

b數組裝得是字首和

dp1[i]

[j]=

min(dp1[i]

[j],dp1[i]

[k]+dp1[k+1]

[j]+b[j]

-b[i-1]

);dp2[i]

[j]=

max(dp2[i]

[j],dp2[i]

[k]+dp2[k+1]

[j]+b[j]

-b[i-1]

);

4.附上ac**+注釋、

//#include

#include

#include

#include

#define maxn 205

using namespace std;

int dp1[maxn]

[maxn]

;int dp2[maxn]

[maxn]

;int a[

305]

;int b[

305]

;int n;

const

int inf =

1e9;

intmain()

for(

int i=

1;i<=n*

2;i++

)for

(int l=

2;l<=n;l++

)//區間長度 }}

int f1=

1e9+1;

int f2=-10

;for

(int i=

1;i<=n;i++

) cout

}

P1880 NOI1995 石子合併(區間dp)

題意 一串環形的數,每相鄰的兩個數可以合併,加上價值,價值是兩個數的和,求最大和最小價值。思路 區間dp板子,有一點要注意因為是環形的數,首位和末尾也是可以合併的,因此可以將原陣列,再往後加一遍。就變成鏈型的了。includeusing namespace std define ll long lo...

P1880 NOI1995 石子合併(區間dp)

題目 description n堆石子擺成一圈,現在要合併成一堆,每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。計算出合併的最大分和最小分。solution 區間dp,分階段劃分問題。由於石子圍成了環,現在把環轉化為兩倍長的鏈。變成 2 n 1 堆,其中第 i 堆與第...

區間DP 洛谷P1880石子合併題解

典型的區間dp,我們可以建立狀態f i j 表示將區間 i,j 內的石子合併的最大值。那麼我們可以把 i,j 分為 i,k 和 k 1,j i k那麼可以推出狀態轉移方程 其中s陣列是表示字首和的,提前預處理了區間內的石子合併總分。另外有乙個要注意的地方,如果直接從前往後列舉區間的左右端點,那麼因為...