大家好,我是连人。本期我们讨论最大子段和的第一个推广问题:最大子矩阵和问题。
最大子段和问题:
首先先简单介绍一下最大子段和问题:在数组a中存放着n个整数,求i,j∈[0,n](i<j)使i和j区间内所有整数相加和最大。
如果a数组内全是负数,则最后结果记为0。
针对这个问题,我们设立一个变量b,b的规则是:
当b[j-1]>0时,b[j] = b[j-1] + a[j]
否则b[j] = a[j]
因此b[j]的动态规划递归式为b[j]=max{ b[j-1] + a[j] ,a[j] }
因为在判断b[j]取值时只需要b[j-1],为了节省空间,直接将数组的预算砍成一个变量b,这个变量的目的以通俗的话讲就是抛弃负数留下正数。
下面为代码:
def max_sum_1(n, a):
sum = 0
b = 0
for i in range(0, n):
if b > 0:
b += a[i]
else:
b = a[i]
if b > sum:
sum = b
return sum
最大子矩阵和问题
将最大字段和问题引申,给定一个矩阵,求一子矩阵的和,使该子矩阵中元素和是所有子矩阵元素和最大的一个。
对于这个问题,可以将“矩阵的和”通过叠放转化为最大子段和问题中的数组,然后将这个数组再通过最大子段和问题找出sum。
步骤如下图。
此时b数组值如图,根据max_sum_1可知7,3是最大字段和10,指代A2:A3矩阵,计入sum。
之后再次向下:
此时b数组值如图,最大子段4,-1,-1,4,和为6,指代A1:B4矩阵,但由于6<10,因此不计入sum,继续向下遍历。
此时b如图,最大子段7,-3,3,9,和为16,指代A1:C4,由于16>10,sum被取代为16,接着向下循环。
第二轮的循环从B行开始,然后重复上述循环。
下面是代码:
def max_sum_2(m, n, a):
sum = 0
for i in range(0, m):
b = []
for k in range(0, n):
b.append(0)
for j in range(i, m):
for k in range(0, n):
b[k] += a[j][k]
max = max_sum_1(n, b)
if max > sum:
sum = max
return sum
转载注明出处。