dp基础之难点解析Minimum Adjustment Cost

该博客探讨了如何解决数组A转换成满足相邻元素差不超过Target的数组B的最小修改代价问题。通过动态规划方法,计算从A到B的最优转换路径,其中涉及到f[i][j]的状态转移方程和初始条件。最终实现的时间复杂度为O(100^2 * n),空间复杂度可优化至O(100)。
摘要由CSDN通过智能技术生成

问题:给定数组A,每个元素是不超过100的正整数,将A中每个元素修改,使得变成数组B,要求是
数组B中任意两个相邻元素之间的差不超过Target,求最小的修改代价,即|A[0]-B[0]|+...+|A[n-1]_B[n-1]|的最小值
例:
A = [1,4,2,3],Target = 1
输出:2(B = [2,3,2,3])


问题分析:首先无论怎么修改,B中的元素肯定是在1和100之间,因为改好的B中如果有大于100的,那么我们肯定可以把这个元素改成100,肯定也满足要求。
最后一步,将A改成B,A[n-1]改成X,这一步的代价是|A[n-1]-X|,同时需要保证|X-A[n-2]|<=Target
接下来需要知道把A[0,...,n-2]改成B[0,...,n-2]的最小代价,且B中任意两个元素之间的差不超过Target,但是有一个问题
在把A[n-1]改成X时,不知道B[n-2]是多少,只有知道了B[n-2]是多少,我们才知道X可以修改的范围是B[n-2]-Target到B[n-2]+Target之间,因为两者距离要小于Target,为此,我们把这个记录下来。

设:f[i][j]表示把A的前i个元素改成B的最小代价且B中任意两个元素之间的代价不超过Target,
并且此时把A[i-1]改成j(即B[i-1]=j;j肯定是在1-100之间)
这样我们就知道,A[i-1]改成j,A[i-2]所修改后的值k的范围要在j-Target到j+Target之间。且k肯定在1-100之间,
    f[i][j] = min{f[i-1][k] + |j - A[i-1]|(j-Target<=k<=j+Target,1<=k<=100)}

初始条件:A的第一个元素可以变换成任意元素,因为之前已经没有相邻元素了,
    f[1][j] = |j-A[0]|(j=1,...,100)

计算顺序:
    f[1][1]...f[1][100]
    .
    .
    .
    f[n][1]...f[n][100]
答案:min(f[n])

时间复杂度O(100^2*n),空间复杂度O(100*n),可以优化至O(100)

 

代码及注释如下:

import sys
def min_adjust_cost(A,Target):
    n = len(A)
    f = [[sys.maxsize for i in range(100+1)] for j in range(n+1)]
    #初始条件f[1][j] = |j-A[0]|(j=1,...,100)
    for j in range(1,100+1):
        f[1][j] = abs(j-A[0])
    #f[i][j] = min{f[i-1][k] + |j - A[i-1]|(j-Target<=k<=j+Target,1<=k<=100)}
    for i in range(2,n+1):
        #把A[i-1]改成B[i-1]=j
        for j in range(1,100+1):
            f[i][j] = sys.maxsize
            #此时要枚举前一个元素改成k,k是要在j-Target和j+Target之间的,且k也是在1到100之间的
            for k in range(j-Target,j+Target+1):
                if k < 1 or k > 100:
                    continue
                #f[i][j] = min{f[i-1][k] + |j - A[i-1]|
                f[i][j] = min(f[i][j] , f[i-1][k] + abs(j - A[i-1]))
    return min(f[n])
A = [1,4,2,3]
Target = 1
print(min_adjust_cost(A,Target))
#输出2

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值