由n个数组成的数组a[n],找出m个子段(不可重复),要求其和最大
方法一、遍历,总共有C(n+1,m)C(n+1,m)中情况,时间复杂
方法二、动态规划
最关键的是
b(i,j):表示数组a的前面j项中有i个子段的最大值,且最后一个子段包含a[j];
maxb(m,j)(m=<j<=n)
故该问题转化为求数组b
b(i,j)=max{b(i,j-1)+a[j],maxb(i-1,t)(t...i-1...j-1)+a[j]};
b的递归式的理解是关键,将其分为最后一个子段仅仅包含a[j],和至少包含a[j-1]a[j],即最后一子段至少含有两个元素
算法主要在于计算b[m][n],并找出第m行的最大值
程序中为了便于计算b[m][n],增设初始化值,即首行值均为0,首列值也均为0.从b[1][1]计算其,且若i>j,则无意义。
在程序中,b数组应该有m+1行n+1列,且公式中应用a[j]时,应改为a[j-1],这与数组中从0开始,以及b[..][0]时不关乎数组有关。
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(void)
{
int a[11]={1,-2,3,4,-3,2,7,6,-2,-1,4};
int m=3,n=11;
if(n<m||m<1) return 0;
int b[4][12]={0};
for(int i=0;i<=m;i++)
b[i][0]=0;
for(int j=1;j<=n;j++)
b[0][j]=0;
for(i=1;i<=m;i++)
for(j=i;j<=n;j++)
if(j>i)
{
b[i][j]=b[i][j-1]+a[j-1];
for(int k=i-1;k<j;k++)
if(b[i][j]<b[i-1][k]+a[j-1])
b[i][j]=b[i-1][k]+a[j-1];
}
else
{
b[i][j]=b[i-1][j-1]+a[j-1];
cout<<i<<" "<<j<<" "<<b[i][j]<<endl;
}
int sum=0;
for(i=0;i<4;i++)
{
for(j=0;j<12;j++)
cout<<b[i][j]<<" ";
cout<<endl;
}
for(j=m;j<=n;j++)
if(sum<b[m][j])
sum=b[m][j];
cout<<sum<<endl;
system("PAUSE");
}
算法的改进,在于存储空间,因为最后只需要b[m]行的最大值,所以只要保存前一行来计算下一行,到第m行时保留最大值即可