动态规划-区间DP

动态规划-区间DP

1. 区间DP的概念

    区间DP,顾名思义就是在一个个的区间上进行DP。

2. 区间DP问题-石子合并

    https://www.acwing.com/problem/content/284/

img
img

    我们还是从动态规划的两个角度来阐述该问题。
        1.  状态表示
            本问题,我们可以用二维状态来表示。即,f[i,j]。那么,该二维状态所表示的集合为:所有将第i堆石子到第j堆石子合并成一堆石子的合并方式的集合。属性为:所有合并方式的总代价的最小值。
        2.  状态计算
            我们如何将f[i,j]划分为一个个的子集呢?我们发现,无论是哪一种合并方式,最后一步都是将两堆合并成一堆。因此,我们可以按照最后一步的合并情况来进行划分。
            2.1 左边为1堆,右边为s-1堆所聚成的一堆。用区间表示:左边:[i,i],右边:[i+1,j]
            2.2 左边为2堆聚成的一堆,右边为s-2堆所聚成的一堆。左边:[i,i+1],右边:[i+2,j]
            ...
            2.s-1 左边为s-1堆聚成的一堆,右边为1堆。左边:[i,j-1],右边:[j,j]。
            在上述子集中,s代表从i堆到j堆的石堆总数。即:s = j - i + 1;
        我们可以将上述的子集划分,归纳成一般情况:
            最后一步的合并情况:
                实际上就是[i,k][k+1,j]两个区间进行合并。其中,k从i~j-1
    根据上述的情况,我们可以发现:在最后一步的合并情况中,都是将两个石堆合并成一个石堆。因此,我们可以将每个合并情况中的合并步骤去掉(这样的话,不会影响最小值,因为最后一步的合并所花费的代价相等),然后再加上这个最后一步合并所花费的代价即可。
    因此,状态转移方程:
        f[i][j] = min(f[i,k] + f[k+1,j] + s[j] - s[i-1])
        其中,s[j] - s[i-1] 为最后一步合并所需要的代价(第i个石堆到第j个个石堆的质量之和)(通过前缀和算法来进行求解即可)。
              k从i~j-1。
    需要注意的就是:由于DP问题在计算某个状态时,该状态之前的状态都已经计算好了。因此,在区间DP中,我们在计算状态时,需要按照区间的长度来进行遍历。因为在状态计算的时候,都是将该区间的子区间进行合并。因此,我们需要按照区间长度从小到大来进行遍历。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 310;

int s[N];

int f[N][N];

int n;


int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&s[i]);
    }
    //求解前缀和数组
    for(int i=1;i<=n;i++){
        s[i] += s[i-1];
    }
    //状态计算
    //按照区间长度从小到大遍历
    //先计算区间长度小的区间状态,再计算大的
    //这样的话,就可以保证题目正确
    //len=1的时候,只有一个石堆,不需要代价。
    for(int len=2;len<=n;len++){
        //遍历区间
        //假设,i为左端点,右端点为x,则:len = x - i + 1 => x = len + i - 1;
        for(int i=1; len + i - 1 <=n;i++){
            int l = i;
            int r = len + i - 1;
            f[l][r] = 0x3f3f3f3f;
            //遍历最后一步的划分情况
            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]);
            }
        }
    }
    printf("%d",f[1][n]);
    return 0;
}
    作者:gao79138
    链接:https://www.acwing.com/
    来源:本博客中的截图、代码模板及题目地址均来自于Acwing。其余内容均为作者原创。
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @   夏目^_^  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示