问题描述
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
输入格式
输入第一行包含一个整数n,表示石子的堆数。
接下来一行,包含n个整数,按顺序给出每堆石子的大小 。
接下来一行,包含n个整数,按顺序给出每堆石子的大小 。
输出格式
输出一个整数,表示合并的最小花费。
样例输入
5
1 2 3 4 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]; } }