1. 程式人生 > >石子歸併--51nod

石子歸併--51nod

題目描述

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;
}