传送门
突然发现如果没有一个传送门的话,之后要是想在线评测会比较麻烦,所以还是得加上原题链接
给定多个元素,每一次把可以把相邻的两个元素合并,两个元素合并的和做一个累加,这个累加的结果作为答案,最后数组里面只剩下一个元素,结束操作,求答案的最小值
4
1 3 5 2
22
n<=300
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int a[N];
int s[N];
int dp[N][N];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int l=i,r=i+len-1;
dp[l][r]=1e8;
for(int j=l;j<=r;j++)
{
dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]+s[r]-s[l-1]);
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}
首先假设是暴力枚举的话,时间复杂度是 ( n - 1 ) ! ,n==300.时间复杂度不符合要求
考虑使用 dp 来进行求解,dp 是一个元素表示一类元素的集合,所以是一种优化方式
状态转移的时候,每一次更新是把相邻的两个元素合并,所以需要枚举分界点,分界点可以是第一个元素一直到倒数第二个元素,如果到最后一个元素就只剩下一个元素,讨论将没有意义
长度是1的话,不需要进行操作,答案是0,全局变量初始值为0,所以长度从2开始变化,一直到最大长度n
然后枚举点,len表示的是数组的长度,i 表示的是数组的起点,起点从1 开始,假设长度是1 ,从1 开始,结束的时候应该还是1 ,但是1+1=2,这里需要注意下,就是加上长度需要减去1才是结尾的元素,靠特殊例子我们可以准确认识到这个问题,这个非常常见,最好记住
i+len-1表示结尾的点
左右边界表示的是把左右边界的元素进行合并,一个区间我们把它分成两个部分,前面一部分取最小值,后面一部分取最小值,然后加上部分和(前缀和处理出来的),部分和表示的是合并的这个过程,不然DP数组没有初始值,不停地状态转移,状态计算也没有用
前缀和比较简单,这里就不再赘述
可以参考这一边博客了解前缀和或者复习前缀和