【现代程序设计】【Homework-01】
1维的最大子数组之和
对于1维的最大子数组之和
假设f[i]表示:对于1..i这个序列中,包含i这个元素的最大序列的值
则对于f[i],0<i<=n;
应该有
f[i]=max(a[i],f[i-1]+a[i]);
f[1]=a[1];
由此一维的问题即可解决
时间复杂度:O(n);
空间复杂度:O(n);
2维的最大子数组之和
为了叙述的方便,在此我们先约定,输入的矩阵为P,行和列值分别约定为m,n
对于2维数组,我们虽然无法直接使用1维中的动态规划的思路
但是,如果我们可以把一整行看做一个元素
按照1维的思路,我们就可以得到一个最大的m*x的矩阵A,0<x<n
显然A不一定是最后的答案,因为矩阵A的行值被我们限定为了m
所以我们需要枚举m,即m←1..m
之后要做的就很简单了
枚举行值等于m,列值恒定为n的所有矩阵D,并找出D中的最大子矩阵E
对于所有的E,max(E)就是最后的答案
时间复杂度=T[求1维最大子数组]*T[枚举矩阵]*T[计算矩阵每一行的值]
前者已知为O(n)
枚举矩阵则需要一个二重的循环,即为O(n^2)
对于计算矩阵D中没一行的值
我们可以进行预处理
假设D在P中的位置为:第x列→第y列
如果我们用一个数组g[i][j]表示:第i行的1..j列的元素之和为g[i][j];
则对于D中的每一行的和应该为g[i][y]-g[i][x],(0<i<=m)
每次计算的复杂度为O(1)
所以总的时间复杂度为:O(N^3)
空间复杂度:
主要用于存储P,D,E
为:O(n^2);
曲面2维的最大子数组之和
曲面和平面最本质的区别就是:边缘的连续问题
所以我们只需要增加3个矩阵P1,P2,P3,排列为:
P P1
P2 P3
求解其中和最大的子矩阵E即可
但对于E,行列值均应分别小于m,n;
时间空间复杂度均和2维平面最大子数组之后的复杂度相同
时间复杂度:O(n^3);
空间复杂度:O(n^2);
以下是作业所需要包含的必要的东西
开发时间:30min
效率:不知道该如何描述
心得:第一次写Blog,把自己所想的准确的表达出来,也不是想象中那么简单
截图:这是一个在线OJ的评测截图,因为有个题目和这个一样,所以我就偷了个懒,没有自己写测试数据 : ]
下面是二维平面最大子数组的源码,由于比较简短,我也就没有做过多的注释
如果有不明白或者觉得本人写的代码不够简洁或者有误,也欢迎各位留言
1 #include<stdio.h> 2 #define M 100 3 #define max(a,b) (a)>(b)?(a):(b) 4 5 6 7 /* 8 9 由于比较懒,在此我先预处理了P的所有子矩阵的,每一行的值 10 11 所以开销为O(n^3) 12 13 但此算法的空间复杂度是可以为o(n^2)的 14 15 但需要每次初始化一下数组的值 16 17 所以我就比较懒的开了个O(n^3)的复杂度 : ] 18 19 */ 20 21 int f[M][M][M],g[M][M][M],a[M][M],i,j,k,l,n,m; 22 23 main() 24 { 25 //输入 26 scanf("%d%d",&m,&n); 27 for(i=0;i<m;i++) 28 for(j=0;j<n;j++) 29 scanf("%d",a[i]+j); 30 31 32 //预处理矩阵每一行的值 33 for(i=0;i<m;i++) 34 for(j=0;j<n;j++) 35 for(k=j;k>=0;k--) 36 g[i][j][k]=g[i][j][k+1]+a[i][k]; 37 38 39 //C中,防止指针值越界,而提前处理初值 40 for(i=0;i<n;i++) 41 for(j=0;j<=i;j++){ 42 f[0][j][i]=g[0][j][i]; 43 l=max(l,f[0][i][j]); 44 } 45 46 47 //求解过程 48 for(i=1;i<m;i++) 49 for(j=0;j<n;j++) 50 for(k=0;k<=j;k++){ 51 f[i][j][k]=max(g[i][j][k],f[i-1][j][k]+g[i][j][k]); 52 l=max(l,f[i][j][k]); 53 } 54 55 printf("%d",l); 56 57 }