在乙個圓形操場的四周擺放著n 堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2 堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。
程式設計任務:
對於給定n堆石子,程式設計計算合併成一堆的最小得分和最大得分。
輸入包括多組測試資料,每組測試資料報括兩行。
第1 行是正整數n,1<=n<=100,表示有n堆石子。
第2行有n個數,分別表示每堆石子的個數。
對於每組輸入資料,輸出兩行。
第1 行中的數是最小得分;第2 行中的數是最大得分。
44 4 5 9
4354
一道明顯的dp
f[i][j]為合併從i到j的最小代價,f2[i][j]為合併從i到j的最大代價
方程:f[i
][j]
=max
(f[i
][k]
+f[k
+1][
j]+s
[j]−
s[i−
1])(
i<=k
f[i][j]=max(f[i][k]+f[k+1][j]+s[j]-s[i-1])(i<=kf[ i][j ]=ma x(f[ i][k ]+f[ k+1] [j]+ s[j] −s[i −1]) (i<=k f [i ][j] =min (f[i ][k] +f[k +1][ j]+s [j]− s[i− 1])( i<=k f[i][j]=min(f[i][k]+f[k+1][j]+s[j]-s[i-1])(i<=kf[ i][j ]=mi n(f[ i][k ]+f[ k+1] [j]+ s[j] −s[i −1]) (i<=k s[i]為從i至1的和 上**: #include using namespace std; int n,a[ 300] ,s[300 ],dp[ 300] [300][ 2];int main() for( int i= 1;i<= 2*n;i++ ) s[i] =s[i-1] +a[i] ;for (int l= 1;l)for (int i= 1,j=i+l;j< 2*n&&i< 2*n;i++ ,j=i+l) }int mx= 0,mn= 0x7f7f7f7f ;for (int i= 1;i<=n;i++ ) cout }另一種**: #include using namespace std; int n,a[ 300] ,s[300 ],dp[ 300] [300][ 2];int main() int mx2= 0,mn2= 0x7f7f7f7f ;for (int i2= 1;i2<=n;i2++)} int mx= 0,mn= 0x7f7f7f7f ; mx= max(dp[1] [n][0] ,mx) ; mn= min(dp[1] [n][1] ,mn) ; mn2= min(mn2,mn) ; mx2= max(mx,mx2);} cout }還有第3種: 見我的新部落格 先從線性的開始吧。有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。樣例 輸入 3 1 2 3 7 13 7 8 16 21 4 18 輸出 9 239 ... 石子歸併最簡單的情況是一排石子,典型的區間dp問題。dp i j 的含義是區間 i,j 合併之後的最大或最小花費 轉移方程 dp i j max min dp i j dp i k dp k 1 j val i,j 對於區間 i,j 它可以由區間 i,k 和區間 k 1,j 合併而來,合併時,要加上... 傳送 這是乙個年代久遠的區間dp 好像以前培訓的時候講了,但是現在才想起來去a 區間dp常用狀態 f i j 以i為左端點,j為右端點的最優解 第一層迴圈列舉區間長度,第二層迴圈列舉起點,第三層列舉中間的斷點 貌似寫到這裡這個題就寫完了 特點 問題能轉換為兩兩合併的問題 such as 能量項鍊,石...#include
#include
p1880 石子合併
P1880 石子合併
P1880石子合併