APP下载

一种改进的最大m子段和算法设计*

2014-06-21廖作斌

湖北科技学院学报 2014年3期
关键词:斜线数组整数

廖作斌

(泉州师范学院 数学与计算机科学学院,福建 泉州 362000)

最大m子段和问题是ACM/ICPC程序设计竞赛典型而且常见的算法题型,其描述如下:给定由n个整数(可能为负)组成的序列a1,a2,a3,……,an,以及一个正整数m,要求确定序列的m个不相交子段,使这m个子段的总和最大!亦即,给定n个整数求这n个数划分成互不相交的m段的最大m子段和。

最大m子段和的经典动态规划优化方法是:设b(i, j)表示前i个数划分成j段,且包括第i个数的最大m子段和,那么有状态转移方程:

b[i][j]=max{b[i-1][t],b[i][j-1]}+a[j] (1<=i<=m, i<=j<=n, i-1<=t

初始条件:b[t][0]=0(0<=t<=m),b[0][t]=0(1<=t<=n)

max{b(m,j)}(m<=j<=n)即为n个整数序列的最大m子段和问题最终解。

算法基本思想为按上述状态转移方程构造一个m+1行(假设第0~m行),n+1列(设第0~n列)的二维数组b,则第m行的最大元素为问题最终解。但实际设计算法时不必构造二维数组,因为只有第m行的最大元素为问题最终解,因此不必保存中间结果,经优化后得到如下经典算法:

int MaxSum(int m,int n,int *a) {

int i,max,j,sum;

if(n

int *b=new int[n+1]; int *c=new int[n+1];

b[0]=0;

for(i=1;i<=m;i++) {

b[i]=b[i-1]+a[i]; c[i-1]=b[i]; max=b[i];

for(j=i+1;j<=i+n-m;j++) {

b[j]=b[j-1]>c[j-1]?b[j-1]+a[j]:c[j-1]+a[j];

c[j-1]=max;

if(max

}

c[i+n-m]=max;

}

sum=0;

for(j=m;j<=n;j++)

if(sum

return sum;

}

算法1 动态规划常规算法

一、常规算法分析

下面对常规算法进行分析,计算过程如图1所示:

图1 常规算法计算过程

算法中需要两个长度为n+1的辅助数组b和c,数组b用于保存第i行的数值,需要计算i+n-m个数值(因为最终解是最后一行的最大值,按状态转移方程,需要已知第m-1行第1~n-1列的数值,以此类推,如图1斜线所示);数组元素c[j]表示当前行从第一个元素到第j个元素的最大值,同样也需要计算i+n-m个数值。

该算法虽然已经过优化,不必计算整个二维数组,只需保存一行数值以及该行从第一个数值到任一数值的最大值,而且不需要计算每一行的全部数值(如图1),但进一步分析发现,当计算第i行时,前面i-1个数值是无意义的,因为分成i段必须保证不少于i个数值,因此每一行需要计算的数值其实是一样的,即n-m+1个。计算过程如图2所示,图中斜线部分即每一行需要计算的数值。

图2 改进后的计算过程

另外,只需要设置一个中间变量表示当前行从第一个元素到第j个元素的最大值,而不必设置数组c。而且,在计算每一行数值时,可以在计算的过程中把每一行的最大值算出,不必在得出最后一行数据后再来查找最大值。

二、算法的改进

根据上述分析,对本算法进行改进:只需设置一个辅助数组b,维数是n-m+1,用于保存当前行n-m+1个数值,对应图2的斜线部分数据,每计算新的一行,数组b中的元素都会被新的值替代;premax_to_i用于保存上一行第一个数字至第i个数字的最大值,curmax用于保存当前行的最大值。

改进后的算法如下:

int MaxSum(int m,int n,int *a) {

int i,index,premax_to_i,curmax;

if(n

int *b=new int[n-m+1];

for(i=0;i

for(index=1;index<=m;index++) {

premax_to_i=b[0];

b[0]=b[0]+a[index-1];

curmax=b[0];

for(i=1;i

if(b[i]>premax_to_i) premax_to_i=b[i];

b[i]=premax_to_i>b[i-1]?

premax_to_i+a[i+index-1]:b[i-1]+a[i+index-1];

if(b[i]>curmax) curmax=b[i];

}

}

delete[] b;

return curmax<0?0:curmax; //若最大值为负数,返回0

}

算法2 改进后的动态规划算法

三、算法示例

假设有5个整数{-2,2,3,8,-5},现要找出3个不相交字段,使这3个子段的总和最大,利用上述改进的算法2,结果如下:

输入: 输出:

3 5 13

-2 2 3 8 -5

数组b的计算过程如下:

图3 数组b的计算过程示例

因为在每次计算数组b时,同时得出每一行的最大值,而最后一行的最大值即为最终结果。

四、结 语

利用改进后的动态规划算法,其时间复杂度虽然仍为O(m*(n-m)),但却只用到一个中间数组,空间复杂度为O(n-m),对于本算法的执行效率还是有显著改善的。

参考文献:

[1]王晓东. 计算机算法设计与分析(第3版) [M]. 北京:电子工业出版社,2007.63~64.

猜你喜欢

斜线数组整数
JAVA稀疏矩阵算法
JAVA玩转数学之二维数组排序
一类整数递推数列的周期性
Excel数组公式在林业多条件求和中的应用
寻找勾股数组的历程
疯狂的游戏
趣味数独
更正启事
答案
求整数解的策略