P1880 NOI1995 石子合併

2021-09-26 08:56:10 字數 1369 閱讀 8379

這次還是給大家講解一下dp

我們則需要根據這個題目的實際含義進行變通即可.

而區間dp的大致模板是:

for (int len=2;len<=n;len++)

for (int i=1;i+len-1<=n;i++)

那講到這裡就很自然(一點都不自然)的引入了今天我們要看的一道題,剛才我已經說了最長不下降子串行是線性dp的模板題,那麼今天說的這道石子合併就是區間dp的經典模板。下面來講解一下我們先看這道題的題目描述以及輸入輸出資料點。(如下)

題目描述

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

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

輸入格式

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

輸出格式

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

輸入輸出樣例

輸入 #1 複製

44 5 9 4

輸出 #1 複製

4354

那麼上面就是這道題目的內容,即每次進行合併的時候就是合併乙個區間.

我們可以設f[i][j]為合併i-j區間的石子的最優方案即最小花費,假設在我們進行i和j的狀態轉移的時候必然更小的區間已經求出了最優的方案數,那麼我們只需要用k去劃分石子數去進行狀態轉移即可.

因為本來的時間是o(n^3),我們則需要優化時間,採用字首和的方法,把合併的數量進行計算即可.

我們可以得到狀態轉移方程:

f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+cost[i][j])

表示兩堆石子的合併花費加上新的花費得到的結果.

在**實現上,我們需要注意:len是從2開始的,諸如f[1][1],f[2][2]都是不需要花費價值的,即初始值0;狀態轉移方程是f[i][k]+f[k+1][j]+cost[i][j]) 而不是f[i][k]+f[k][j]+cost[i][j])合併的是兩堆不同的石子而不是一堆,這點需要注意.

**如下:

#include#includeusing namespace std;

int a[210],f1[210][210],f2[210][210];

int main()

for(int i=1;i<=2*n;i++)

for(int r=2;r<=n;r++)

cout

}

P1880 NOI1995 石子合併

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

P1880 NOI1995 石子合併

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

P1880 NOI1995 石子合併

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