题目链接 https://www.jisuanke.com/course/709/36587
题解: LeetCode里面有个戳气球的题和这个类似,用区间dp来解。
由于n堆(n>=2)石子合并,最终一定会有个只剩2堆石子的中间状态,这个状态就是突破口。
最终的2堆石子一定是在原来的石子里面连续的,可以用dp[i][j]表示区间i..j的石子合并后最小的体力消耗,
n堆石子消耗的最小体力为dp[1][n],先将石子合并来只剩2堆,只需要枚举2堆石子的边界即可,最后再将2堆石子合并为1堆。所以状态转移方程为dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[i][j]) (i<=k<j),sum[i][j]表示i..j区间的石子重量和
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 0x3fffff
using namespace std;
int n;
int a[100];
int dp[100][100];
int Count[100];// 统计区间和
int main() {
scanf("%d",&n);
for(int i = 1;i <= n;i++) {
scanf("%d",&a[i]);
Count[i] = Count[i-1] + a[i];
// printf("%d ",Count[i]);
}
// printf("\n");
// 区间dp
// 枚举区间长度
for(int len = 2;len <= n;len++)
// 区间起点
for(int i = 1;i <= n;i++) {
if(i+len-1>n) break;
//dp[i][i+len-1] = ;
// 最后剩2堆石子,枚举左边那堆石子的右边界
int t = MAXN;
for(int k = i;k < i+len-1;k++) {
t = min(t,dp[i][k]+dp[k+1][i+len-1]+Count[i+len-1]-Count[i-1]);
}
dp[i][i+len-1] = t;
// printf("dp[%d][%d]=%d\n",i,i+len-1,t);
}
printf("%d\n",dp[1][n]);
return 0;
}