一道比较经典的区间DP,和这题一样:点击打开链接
用dp[i][j] 表示消掉区间[i,j]内所有数字后的最优解。 那么状态转移为ans = min(ans,dp(i,k-1)+a[k]*a[i-1]*a[j+1]+dp(k+1,j)); 这个状态转移表示的是对于区间[i,j]最后杀k。 为什么要这么转移呢? 因为你选择的这个数字,其左右的数字会对其产生影响,而这样表示就可以巧妙的消除这个影响,而把问题转移给其子问题。既然最后选择k那么获得的分数自然就是a[k]*a[i-1]*a[j+1] 了。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<numeric>
#include<functional>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<cassert>
#include<complex>
#include<iomanip>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 205;
const int INF = 1000000000;
int T,n,kase=0,a[maxn],b[maxn],d[maxn][maxn];
int dp(int i, int j) {
if(i > j) return 0;
int& ans = d[i][j];
if(ans != -1) return ans;
ans = INF;
for(int k=i;k<=j;k++) ans = min(ans,dp(i,k-1)+a[k]*a[i-1]*a[j+1]+dp(k+1,j));
return ans;
}
int main() {
while(~scanf("%d",&n)) {
memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
a[n+1] = b[n+1] = 1;
int ans = dp(2,n-1);
printf("%d\n",ans);
}
return 0;
}