最大m子段和问题

由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行时保留最大值即可

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值