非常经典的区间dp题啊,这种题的数据结构不大,可以从一些比如n3复杂的的方式入手
对于状态转移方程,区间[a,b]与[x,y]合并,代价就是:两个区间之前合并到这一步所记录的代价+他们自己的代价。也就是说我们需要维护两个数组:dp与presum来分别记录路径代价与区间重量总和,对于每个大的区间,可以用经典的选取中间点的方式来转移
dp[l][r] = min(dp[l][r],dp[l][m] + dp[m + 1][r] + sum[l][r]);
为了做到不重不漏,循环可以先枚举右端点,之后枚举左端点从大到小一直接近0,之后对于每个左右区间,找中间截断点m,之后状态转移即可
AC代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin>>n;
vector<int> num(n,0);
for(int r = 0;r < n;r++)
{
cin>>num[r];
}
vector<vector<int>> dp(n + 7,vector<int>(n + 7,LLONG_MAX));
vector<vector<int>> sum(n + 7,vector<int>(n + 7,0));
for(int y = 0;y < n;y++)
{
for(int u = y;u >= 0;u--)
{
sum[u][y] = sum[u + 1][y] + num[u];
}
}
for(int r = 0;r < n;r++)
{
dp[r][r] = 0;//只是“合并价值”
}
for(int y = 1;y < n;y++)
{
dp[y - 1][y] = num[y - 1] + num[y];
}
for(int r = 2;r < n;r++)
{
for(int l = r - 2;l >= 0;l--)
{
for(int m = l;m < r;m++)
{
dp[l][r] = min(dp[l][r],dp[l][m] + dp[m + 1][r] + sum[l][r]);
}
}
}
cout<<dp[0][n - 1]<<endl;
return 0;
}