算法提高 合并石子【动态规划】

问题描述
  在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
输入格式
  输入第一行包含一个整数n,表示石子的堆数。
  接下来一行,包含n个整数,按顺序给出每堆石子的大小 。
输出格式
  输出一个整数,表示合并的最小花费。
样例输入
5
1 2 3 4 5
样例输出
33
数据规模和约定
  1<=n<=1000, 每堆石子至少1颗,最多10000颗。
题目分析
  这是一道很经典的动态规划题(据说),但是我不会,哈哈哈。我的理解是,逆向考虑这个题,把一堆石头分为两堆。
  因此,设置一个中间点k ,d[ i ][ j ] = min(d[ i ][ n ], d[ 1 ][ k ] + d[k + 1][ j ]),遍历每一个处于[ i , j ]中的每一个中间点k
 
递归实现的话,最后一个样例会超时。
int dp(int i, int j) {
    if (d[i][j] || i==j)    return d[i][j];
    int mi = bigdata;
    for (int ii = i; ii < j; ii++) {
        int t = dp(i, ii) + dp(ii + 1, j);
        if(mi > t)    mi = t;
    }
    return d[i][j] = mi + sum[j] - sum[i - 1];
}

循环实现

for (int i = n - 1; i > 0; i--) {//起点
        for (int j = i + 1; j <= n; j++) {//终点
            long long t = bigdata;
            for (int k = i; k < j; k++) {//中间点
                long long  temp = d[i][k] + d[k + 1][j];
                if (t > temp)    t = temp;
            }
            d[i][j] = t + sum[j] - sum[i - 1];
        }
    }
原文地址:https://www.cnblogs.com/woxiaosade/p/10455677.html