# ACwing 282 石子合并(区间dp)
题意
给出N堆石子,每次只能合并相邻的两堆石子,代价为两堆石子的质量和,求合并所有石子的最小代价。
思路
区间dp中i,j
表示的是两个区间的左右端点,操作对象是区间。
dp[i][j]
表示合并第i堆石子到第j堆石子的最小代价。
对于i,j
围成的区间,以合并的分割线区分不同合并方式,相当于在i,j
中插入一块隔板,dp[i][j]
取不同隔板位置进行合并代价的最小值。
本质上就是枚举区间的左右两个端,但是由于在一个区间中加入隔板,分成的两个子区间长度都小于原来的区间,也就是说需要使用到长度小于自身的区间的数据。所以不能直接枚举左右端点,而是枚举长度和左端点,通过长度和左端点算出右端点。
代码
#include <bits/stdc++.h>
using namespace std;
int s[305],f[305][305];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>s[i],s[i]+=s[i-1];
for(int len=2,r,k;len<=n;len++)
for(int l=1;l+len-1<=n;l++){
r=l+len-1;
f[l][r]=2e9;
for(int k=l;k<r;k++)
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
}
cout<<f[1][n];
return 0;
}