动态规划_最大m子段和
来源:互联网 发布:mac相册看图片不方便 编辑:程序博客网 时间:2024/06/10 07:55
继最大子段和在空间上的推广,那么再来看看她在个数上的延伸。
最大子段和就是最大m子段和问题在m=1时的特殊情况
类似最大字段和中的b(j)
这里假设b(i,j)表示数组a的前j项中i个子段和的最大值,且第i个子段含a[j]
其中b(i,j-1)+a[j]表示第i个子段含a[j],而,表示第i个子段仅含a[j],所以在表示b(i,j)需要从有i-1个子段中选择一个最大子段和的字段,即找到一个合适的t.
初始时b(0,j)=0,(0<=j<=n);b(i,0)=0,(1<=i<=m)
int MaxSum(int m,int n,int *a){if(n<m||m<1)return 0;int **b=new int *[m+1];int i,j;for( i=0;i<=m;i++)b[i]=new int [n+1];for( j=0;j<=m;j++) //0....mb[j][0]=0;for(int k=1;k<=n;k++) //1...mb[0][k]=0;for(i=1;i<=m;i++)for(int j=i;j<=n-m+i;j++)<span style="color:#FF0000;"><strong>if(j>i)</strong>{b[i][j]=b[i][j-1]+a[j];for(int k=i-1;k<j;k++) //从有i-1个子段中选择一个最大子段和的字段if(b[i][j]<b[i-1][k]+a[j]) </span> //表示第i个字段仅含a[j],所以需要得到max{b[i-1][k]},这样的b[i][j]才能表示最大i字段和<span style="color:#FF0000;">b[i][j]=b[i-1][k]+a[j];}else //i==j的情况b[i][j]=b[i-1][j-1]+a[j];</span>int sum=0;for( j=m;j<=n;j++)if(sum<b[m][j])sum=b[m][j];printB(b,m,n);return sum;}
例如:a[]={3,-4,2,11,-4,13,-5,-2} m=3
根据以上算法段可得出下表,表中蓝色表示初始化,红色xx表示不存在i>j的情况,即b(i,j)不合实际,紫色o表示该字段仅含一个元素,
例如b(i,j),i=1时,j最多只能为6,然后a[7],a[8]各为一个子段,这样才能构成m=3的子段
重点是绿色数字,表示经过了更新的值。例如绿色2,此时i=2,j=3,根据b(i,j-1)+a[j]=-1+2=1,然后从i-1~j-1,也就是1~2,maxb(i-1,t)+a[j]=0+2=2 由于2>1,所以更新b(2,3)=2
再比如说绿5,1(-1+2)->5(3+2) 绿26,25(12+13)->26(13+13) 绿16,12(1+11)->16(5+11).......
最后在b(3,j)中找最大值,即1,16,12,29,24,24,中,找出29为{3,-4,2,11,-4,13,-5,-2}最大3子段和
算法分析:由此可知该算法时间复杂度为O(m*n^2),空间复杂度为O(m*n)
但是经分析可知计算b[i][j]时只用到了数组b的第i-1行和i行的值,因而算法只要储存b的当前行i和i-1行,没必要储存整个二维数组的值。
改进后算法如下:
int MaxSum(int m,int n,int *a){if(n<m||m<1)return 0;int *b=new int[n+1];int *c=new int[n+1];b[0]=0;for(int k=0;k<=n;k++) //初始化保存上一轮值的数组c[k]=0;for(int i=1;i<=m;i++){b[i]=b[i-1]+a[i]; //第i个字段包含a[i]c[i-1]=b[i]; //<span style="color:#FF0000;">为什么是c[i-1]=b[i]呢?保存当前最大子段和,因为在下一轮即有2,3个子段时,当前的b[i]会作为b[i-1]来计算新一轮的b[i]</span>int max=b[i];for(int j=i+1;j<=i+n-m;j++) //第i个字段仅包含a[i]{b[j]=b[j-1]>c[j-1]?b[j-1]+a[j]:c[j-1]+a[j]; //c[j-1]上一轮的最大值,没有的话默认为0c[j-1]=max; //<span style="color:#FF0000;">非首个成员的话,先是用c[j-1]直接保存上一次最大值,</span>if(max<b[j]) <span style="color:#FF0000;"> //然后更max,用于下一次,这样的c[]在该轮必定是递增的,</span>max=b[j];}c[i+n-m]=max;//<span style="color:#FF0000;">当然在一轮结束的时候c[]也是要保存当前最大子段和max</span> cout<<"b[] ";printA(b,n);cout<<"c[] "; printA(c,n);cout<<endl; }int sum=0; for(int j=m;j<=n;j++)if(sum<b[j]) sum=b[j];return sum;}
运行结果:
红色圆点表示:c[]被更新的地方,
红色斜杠表示:某个子段首个成员更新的情况,如b[1]=3-->c[0]=3,这是直接更新的,但是在计算出b[2]=-1,先是直接赋值c[2],因为此时的最大字段和就是上一次的3嘛,但有所不同的是,这里我会将max和当前最大字段和b[j]比较一下,然后更新,用于下一次的c[j-1]
由此可知该算法的时间复杂度O(m(n-m),空间复杂度为O(n),当m或者n-m为常数时,时间复杂度便可降为O(n)
- 动态规划_最大m子段和
- 【动态规划】最大m子段和
- 动态规划---最大子段和,最大子矩阵和,最大m子段和
- 动态规划入门之最大M子段和
- 17089 最大m子段和(scauoj、dp动态规划)
- 环形m段最大子段和 题解动态规划DP
- 动态规划----最大子段和
- 最大子段和(动态规划)
- 最大子段和动态规划实现
- 最大子段和(动态规划)
- 动态规划 - 最大子段和
- 最大子段和-分治&&动态规划
- 动态规划求解最大子段和
- 动态规划之最大子段和
- 动态规划求最大子段和
- 动态规划之最大子段和
- 动态规划,最大子段和
- 动态规划 最大子段和问题
- Linux下TCP/IP通信
- 易中天经典语录
- iOS开发之打包上传到App Store——(三)申请证书并且发布应用程序到App Store
- 归档文件任务计划
- 红杉资本和IDG
- 动态规划_最大m子段和
- bash: ./a.sh: /bin/bash^M: bad interpreter: No such file or directory的解决方法------dos--->unix
- 只选对的!手游开发者谈第三方支付
- Leetcode OJ #3 Longest Substring Without Repeating Characters
- 点是否在三角形内
- 利用Python实现自动登录
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- Python字符串-非转义和unicode
- Debug和Release区别