在乙個圓形操場的四周擺放著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
#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
}
還有第3種:#include
#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
}
見我的新部落格
p1880 石子合併
先從線性的開始吧。有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。樣例 輸入 3 1 2 3 7 13 7 8 16 21 4 18 輸出 9 239 ...
P1880 石子合併
石子歸併最簡單的情況是一排石子,典型的區間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 合併而來,合併時,要加上...
P1880石子合併
傳送 這是乙個年代久遠的區間dp 好像以前培訓的時候講了,但是現在才想起來去a 區間dp常用狀態 f i j 以i為左端點,j為右端點的最優解 第一層迴圈列舉區間長度,第二層迴圈列舉起點,第三層列舉中間的斷點 貌似寫到這裡這個題就寫完了 特點 問題能轉換為兩兩合併的問題 such as 能量項鍊,石...