问题:给定数组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