題目:
在乙個操場上一排地擺放著n堆石子。現要將石子有次序的合併成一堆。規定每次只選相鄰的2堆石子合成新的一堆,並將新的一堆石子數記為該次合併的得分。
程式設計任務:
設計乙個程式,計算出將n堆石子合併成一堆的最小得分。
1≤n≤100,0≤ai≤200。
擴充套件題目:環形結構上的動態規劃問題
在乙個圓形操場的四周擺放 n 堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。
試設計出乙個演算法,計算出將 n堆石子合併成 1堆的最小得分和最大得分。
輸入格式
資料的第 1行是正整數 n,表示有 n 堆石子。
第 2行有 n 個整數,第 i 個整數 ai 表示第 i 堆石子的個數。
輸出格式
1 行為最小得分
輸入樣例
713 7 8 16 21 4 18
輸出樣例
239我們介紹的線性dp一般從初態開始,沿著階段的擴張向某個方向遞推,直至計算出目標狀態。區間dp也屬於線性dp中的一種,它以「區間長度」作為dp的「階段」,使用兩個座標(區間的左、右端點)描述每個維度。在區間dp中,乙個狀態由若干個比它更小且包含於它的區間所代表的狀態轉移而來,因此區間dp的決策往往就是劃分區間的方法。區間dp的初態一般就由長度為1的「元區間」構成。
這種向下劃分、再向上遞推的模式與某些樹形結構,例如線段樹,有很大的相似之處。我們把區間dp作為線性dp中一類重要的分支單獨進行講解,將使讀者更容易理解以後樹形dp的內容。同時,借助區間dp這種與樹形相關的結構,我們也將提及記憶化搜尋——其本質是動態規劃的遞迴實現方法。
演算法思想:
如果有三堆:4,5,6。
第一種方案:文字解釋:4和5合併成一堆9,然後9再和6合併成15。花費就是4 + 5 + 9 + 6 = 24。 4 + 5是合併前兩堆的花費,在合併後面兩堆得時候需要把這個花費算進去。
第二種方案:文字解釋:5和6合併成一堆11,然後11再和4合併成15。花費就是5 + 6 + 11 + 4 = 26。同上面的花費解釋。
可以明顯看出,當選擇合併的順序不同時,所產生的花費是不同的。
使用dp演算法來解析這個問題:
我們以4 + 5 + 9 + 6 = 24這個方案來解釋dp的思想。我們從數字上來進行解釋(4 + 5)表示的是合併第1,2時花費的費用、9表示第1、2合併之後那堆石子的數目,6是第三堆石子的
我們把這個數目擴充套件一下到 4 堆:4,5,6,7(我們這裡沒有使用最優解) 那麼算式就成了數目。
算式加起來4+5+9+6+15+7=46
46並不是最優解,最優解應該是4+5+6+7+9+13=44。數字不同但是原理是一樣的。最優解怎麼產生呢?4堆可以是1+3 2+2 3+1三種合併方式,列舉就可以。
從上面看出前三堆所構成的花費是由 三部分構成,1、第一二合併的花費;2、第一二合併的個數和;3:第三堆本身個數
通過上面的理解:
f[ i ][ j ]表示合併第i堆到第j堆花費的最小費用,轉移方程為
f[ i ][ j ]=min
其中的sum[j]-sum[i-1]表示從i堆到第j堆石子的數目。
f[ i ][ k ]表示從 i 堆到k堆合併石子的最小花費
f[k+1][ j ]表示從k+1堆到 j 堆合併的最小花費
如果把這f[ i ][ k ],f[k+1][ j ]這兩堆合併起來用的最小費用就是
f[ i ][ k ]+f[k+1][ j ]以前分別合併這兩堆用的費用,
sum[j]-sum[i-1]表示把f[ i ][ k ]、f[k+1][ j ]這兩堆再合併成一堆產生的費用(當然產生的費用是這兩堆石子數的總和,用字首和輕鬆求出)
完整**:
#include
#include
#include
#include
using
namespace std;
int f[
310]
[310
],a[
310]
,sum[
310]
,n;int
main()
for(
int len=
1;len)//列舉區間長度
for(
int i=
1;i<=n-len;i++
)//列舉區間起點
cout<[n]<}
通過上面例子的學習,我們發現解決區間動規問題,都是用迴圈巢狀列舉區間長度和起點,再在區間中間列舉區間分割點,用不同的小區間組成這個區間選最優值。 NOI 1995 合併石子 區間DP
在乙個圓形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行有n個數,分別...
區間dp板子題 noi1995 石子合併
非常經典的區間dp模板 對於每乙個大於二的區間 我們顯然都可以將它拆分成兩個子串行 那麼分別計算對於每個取最優值即可 pragma gcc optimize o2 include include include include include include include include incl...
NOI1995 石子合併
在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.圓的話就用2 n 1,即只有n種情況 include using namespace ...