做了几道区间DP的题,发现大都采用矩阵连乘的状态转移方程
也即类似dp[i][j] = best(dp[i][j], dp[i][k]+dp[k][j])的形式
这道题目想了好久都没想明白怎么表示状态
看了别人的才知道,我们用dp[i][j]表示把a[i]~a[j]的数取完对应结果
很容易有dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]+a[i]*a[k]*a[j])
这里可能理解起来有些困难,其实这样看我们先取完了a[i]~a[k],再取完a[k]~a[j]
因为最后会剩下边界所以剩余的3个数即为a[i], a[k], a[j]
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 110
#define LL long long
using namespace std;
int a[MAXN];
LL dp[MAXN][MAXN];
int main(void) {
int n;
while(~scanf("%d", &n)) {
for(int i=1; i<=n; ++i) {
scanf("%d", &a[i]);
}
memset(dp, 0, sizeof(dp));
for(int i=n-2; i>0; --i) {
dp[i][i+2] = a[i]*a[i+1]*a[i+2]*1ll;
for(int j=i+3; j<=n; ++j) {
dp[i][j] = min(a[i]*a[i+1]*a[j]*1ll+dp[i+1][j], a[i]*a[j-1]*a[j]*1ll+dp[i][j-1]);
for(int k=i+2; k<j-1; ++k) {
dp[i][j] = min(dp[i][j], a[i]*a[k]*a[j]*1ll+dp[i][k]+dp[k][j]);
}
}
}
cout << dp[1][n] << endl;
}
return 0;
}