石子歸併--51nod
阿新 • • 發佈:2018-12-19
題目描述
N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將N堆石子合併成一堆的最小代價。
例如: 1 2 3 4,有不少合併方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
括號裡面為總代價可以看出,第一種方法的代價最低,現在給出n堆石子的數量,計算最小合併代價。
收起
輸入
第1行:N(2 <= N <= 100) 第2 - N + 1:N堆石子的數量(1 <= A[i] <= 10000)
輸出
輸出最小合併代價
輸入樣例
4 1 2 3 4
輸出樣例
19
思路
石子歸併每次將一堆石子和另一堆合併在一起,代價為兩堆石子的數量總和,我們可以知道到最後將要得出結果時一定是隻剩下兩堆,然後一和並即是結果,所以我們可以考慮最後兩堆是如何得來的,使其最小,便可以使最後的結果最小,所以就是將這一長串分成了一個個區間,求最小的區間,來得到最小的結果,便考慮區間dp
AC程式碼
#include<cstdio> #include<iostream> using namespace std; #include<numeric> #include<algorithm> #include<cstring> const int INF=1e7; const int maxn=105; __int64 a[maxn],s[maxn],dp[maxn][maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); partial_sum(a,a+n+1,s); //用stl裡的函式求字首的和,求好後放入s陣列中 for(int d=1;d<n;++d) for(int i=1,j;(j=i+d)<=n;++i) { dp[i][j]=INF; //先給其附最大值 for(int k=i;k<j;++k) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]); } s[j]-s[i-1]即i到j的和 printf("%I64d\n",dp[1][n]); return 0; }