最大m子段和问题:将一个整数序列a1、a2、a3……an分成m段,使其总和最大。
(m=1时是最大子段和问题)
存储设计:
int数组b[i][j]: 当序列a被分成i个子段时, 到第j项截至时的最大子段和。该问题最终的最优解为:max { b(m, j ), (m <= j <= n ) }
递归式:
b(i, j) = max{ b(i, j-1)+a[j], max {b(i-1, t)+a[j], (1 <= t <= m )}} (1 <= i <=m; i <= j <= m )
其中:
b(i, j-1)+a[j]: 第i个子段包含a[j] ;
max {b(i-1, t)+a[j], (1 <= t <= m )}: a[j]独立作为新生成的子段。
代码:
int MaxSumM(int m, int n, int *a)
{
int **b = new int*[m+1] ;
for(int i=0; i <=m; i++) b[i] = new int[n+1];
for(int i=0; i <=m; i++) b[0][i] = 0 ;
for(int i=1; i <=m; i++)
{
b[i][i] = b[i-1][i-1]+a[i] ;
for(int j=i+1; j <=n-m+i; j++)
{
b[i][j] = b[i][j-1]+a[j] ;
for(int k=i-1; k<j; k++)
if(b[i][j] < b[i-1][k]+a[j]) b[i][j] = b[i-1][k]+a[j] ;
}
}
int sum=0 ;
for(int i=m; i<=n; i++)
if(sum < b[m][i]) sum = b[m][i];
return sum ;
}
改进:
空间:实际上,数组b[][]每次只有第i-1行和第i行的值用到,因此只需存储b[][]的当前行即可。
时间:max {b(i-1, t)+a[j], (1 <= t <= m )}的值可以在计算第i-1行时预先存储起来,从而避免的重新计算。
代码:
int MaxSumM(int m, int n, int *a)
{
int *b = new int[n+1] ;
int *MAX = new int[n+1] ;
b[0] = 0;
int i, j ;
for( i=0; i <=m; i++) MAX[i] = 0 ;
for( i=1; i <=m; i++)
{
b[i] = b[i-1]+a[i] ;
for(j=i+1; j <=n-m+i; j++)
{
if(MAX[j-1]<b[j-1])
{
b[j] = b[j-1]+a[j] ;
MAX[j-1] = b[j-1] ;
}
else b[j] = MAX[j-1]+a[j] ;
if(MAX[j-1]<MAX[j-2]) MAX[j-1] = MAX[j-2] ;
}
MAX[j-1] = (b[j-1]>MAX[j-2]) ? b[j-1]: MAX[j-2] ;
}
return MAX[n] ;
}
转载于:https://blog.51cto.com/5372221/919590