# 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;
}
原文地址:https://www.cnblogs.com/sstealer/p/13295996.html