思路
区间dp,也是我写的第一道区间dp题,首先我们先求出来所有的两堆合并的最小代价(最小区间),然后再求所有三个合并的最小代价,依次递推。再算合并的代价时如果一个一个去加就太浪费时间了,所以我们求一个前缀和就好了;
定义表示合并l ~ r区间需要花费的最小体力,首先一堆的时候不用合并所以dp[i][i]=0,其他的初始化为INF。
我们枚举区间长度 len 从2~n,然后在枚举区间起点,把所有的长度为len的区间的最小代价都算出来,那么怎么算长度为len的区间合并的最小代价呢,我们可以通过枚举区间内的点把这个区间分为两部分合并,枚举所有区间内的点求一个最小值即长度为len的区间的最小代价。
状态转移方程为:,a[i]表示前缀和。
我感觉说的好乱啊,看代码可能好一点,我发现dp也是一个大暴力啊,真是暴力出奇迹。没有暴力解决不了的事情。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 205;
const int INF = 0x3f3f3f3f;
int n, a[MAXN], dp[MAXN][MAXN];
int main()
{
while (~scanf("%d", &n))
{
memset(dp, INF, sizeof(dp));
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
dp[i][i] = 0;
a[i] += a[i-1];
}
for (int len = 2; len <= n; len++)
{
for (int l = 1; l+len-1 <= n; l++)
{
int r = l+len-1;
for (int k = l; k < r; k++)
{
dp[l][r] = min(dp[l][r], dp[l][k]+dp[k+1][r]+a[r]-a[l-1]);
}
}
}
printf("%d\n", dp[1][n]);
}
return 0;
}
/*
3
1 2 3
7
13 7 8 16 21 4 18
*/