题目描述 Description
有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。
输入描述 Input Description
第一行一个整数n(
第二行n个整数
输出描述 Output Description
一个整数表示最小合并代价
样例输入 Sample Input
4
4 1 1 4
样例输出 Sample Output
18
题解
写出来普通的区间dp方程,发现时间复杂度是
有一篇叫“动态规划加速原理之四边形不等式”的文章对四边形不等式介绍得很好。
形如本题的状态转移方程都可以用四边形不等式优化,这里不再证明。(实在不会证可以拿优化过的和裸dp的对拍啊,四边形不等式不难写)
这里介绍一下边界:
只有一堆石子时,
只要分析好边界的值是自变量等于什么时取到的,自然可以得到决策变量最大值的边界。以后转移时只需在更新
Code
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 3010, oo = 1000000000;
int f[maxn][maxn], s[maxn][maxn];
int n, a[maxn], w[maxn][maxn];
void init()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
w[i][i] = a[i];
}
for(int i = 1; i <= n; ++i) for(int j = i + 1; j <= n; ++j)
w[i][j] = w[i][j - 1] + a[j];
}
void work()
{
for(int i = 1; i <= n; ++i) s[i][i] = i;
for(int p = 1; p < n; ++p) for(int i = 1; i <= n - p; ++i)
{
int j = i + p;
f[i][j] = oo;
for(int k = s[i][j - 1]; k <= s[i + 1][j]; ++k)
if(f[i][j] > f[i][k] + f[k + 1][j] + w[i][j])
{
f[i][j] = f[i][k] + f[k + 1][j] + w[i][j];
s[i][j] = k;
//因为这里k是递增的,所以不用取max
}
}
printf("%d", f[1][n]);
}
int main()
{
init();
work();
return 0;
}
原文地址:http://blog.csdn.net/t14t41t/article/details/46429571