传送门:牛客
题目描述:
设有N堆沙子排成一排,其编号为1,2,3,\dots ,N1,2,3,…,N(N\leq 300)(N≤300)。每堆沙子
有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合
并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序
不同,合并的总代价也不相同,如有4堆沙子分别为 1 3 5 2 我们可以先合并1、2堆,代价为4,得到4 5 2
又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,
则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总
的代价最小。输出最小代价。
输入:
4
1 3 5 2
输出:
22
这道题的简化版,但是具体的dp想法是一样的,可以说是一道经典的区间dp题
主要思路:
下面是具体的代码部分:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n;int dp[1000][1000];
int a[1000];int sum[1000];
int main() {
n=read();
for(int i=1;i<=n;i++) {
a[i]=read();sum[i]=sum[i-1]+a[i];
}
for(int len=2;len<=n;len++) {
for(int l=1;l<=n-len+1;l++) {
int r=l+len-1;
dp[l][r]=dp[l][l]+dp[l+1][r]+sum[r]-sum[l-1];
for(int k=l+1;k<=r-1;k++) {
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1]);
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}