区间DP循环一般是:
区间长度从小到大来循环,然后再循环区间的左端点,然后再枚举我们的决策。
f[i][j]表示将所有第i堆石子到第j堆石子合并成一堆石子的合并方式,这些方式中代价的最小值
我们可以以最后一次合并的分界线来划分集合
k = i, ..., j - 1
每一类的最小代价 = 左边的最小代价 + 右边的最小代价 + 最后一步的代价
最后对每一类的最小代价取最小值
注:当区间长度为1时(即len = 1),区间不需要合并,代价是0,因为f是全局数组,所以len可以从2开始循环。
算每个f[i][j]的时候,f[i][j]用到的状态都应该已经被算好了。所以我们要有一个顺序,保证要算的这个状态所依赖的状态已经提前被算好了。这里的顺序可以枚举一下区间长度。
我们按照区间长度从小到大来枚举。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 310;
int n;
int f[N][N];
int s[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; ++ i) cin >> s[i];
for (int i = 1; i <= n; ++ i) s[i] += s[i - 1];
for (int len = 2; len <= n; ++ len)
{
for (int i = 1; i + len - 1 <= n; ++ i)
{
int l = i, r = i + len - 1;
f[l][r] = 1e8;
for (int k = l; k < r; ++ k)
{
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
}
}
}
cout << f[1][n] << endl;
return 0;
}