题目链接:哆啦A梦传送门
题意:给一串数字,保留首尾数字,拿掉中间的数字,每拿走一个数字k,贡献就为num[k-1]*num[k]*num[k+1],问:剩下最后首尾数字时,最小贡献时多少?
题解:参考博客:https://www.cnblogs.com/kuangbin/archive/2013/04/30/3051484.html
区间dp。
我们枚举中间数字作为最后被拿走的数字,那么我们就可以开始递归了。
我们为什么枚举最后被拿走的数字,代码有详细注释。
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
///dp[i][j] 为区间范围内的贡献值
int dp[110][110],num[110];
int solve(int i,int j)
{
///剪枝
if(dp[i][j]!=INF) return dp[i][j];
///只剩下两个,说明当前区间贡献值为0
if(i+1==j) return dp[i][j]=0;
///枚举最后拿走的数字
///为什么我们要枚举最后拿走的数字,而不枚举首先拿走的数字?
///假设我们枚举首先拿走的数字,那么递归solve(i,k)中,就不能有数字乘以a[k],
///因为它早就拿走了,而要是我们枚举最后拿走的数字,那么递归solve(i,k)时,
///就能有数字可以乘以a[k],因为它是最后才拿走的
for(int k=i+1;k<j;k++){
dp[i][j]=min(dp[i][j],solve(i,k)+solve(k,j)+num[i]*num[k]*num[j]);
}
return dp[i][j];
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
memset(dp,INF,sizeof(dp));
// printf("%d\n",dp[1][1]);
printf("%d\n",solve(1,n));
return 0;
}