最大子段和是指,对于一段数列来讲,有区间\([l,r]\)使得\(a_i+a_{i+1}+...a_r\)最大,这个最大的和被称为最大子段和。php
扩展内容是求解最大子矩阵和。ios
经过枚举l和r,来枚举全部可能的状况,暴力计算l到r的全部和。c++
代码:算法
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++){ int sum=0; for(int k=i;k<=j;k++) sum+=a[k]; maxx=Max(maxx,sum); }
时间复杂度\(O(n^3)\)数组
咱们能够发现,其实在计算若干个数的和时,有重复计算,咱们能够提早预处理前缀和来避免这个问题,优化时间复杂度。优化
代码:spa
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) maxx=Max(maxx,sum[j]-sum[i-1]);
时间复杂度\(O(n^2)\)code
这个问题能够经过动态规划来解决。get
咱们发现,若是在咱们已经知道以i结尾的最大子段和,那么下一步的决策只有两个:string
咱们设\(f_i\) 表示以i结尾的最大子段和。
状态转移:\(f_i=max(f_{i-1}+a_i,a_i)\)
最终答案为:\(max(f[i]),i=1,2,...n\)
能够发现,状态\(f_i\)已经包括了全部的状态空间,因此最终答案合法。
代码:
for(int i=1;i<=n;i++) f[i]=Max(f[i-1]+a[i],a[i]); for(int i=1;i<=n;i++) maxx=Max(maxx,f[i]);
时间复杂度:\(O(n)\)
最大子矩阵和问题 http://ybt.ssoier.cn:8088/problem_show.php?pid=1282
思路:咱们枚举两行:\(l,r\),并把l到r之间的全部数,压成一个一维数组,即\(c_i=\sum ^r_{j=l} a_{j,i}\),跑一遍最大字段和,对全部结果取max。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<sstream> #include<queue> #include<map> #include<vector> #include<set> #include<deque> #include<cstdlib> #include<ctime> #define dd double #define ll long long #define ull unsigned long long #define N 101 #define M number using namespace std; const int INF=0x3f3f3f3f; int n,a[N][N],sum[N][N],b[N],f[N],maxx=-INF; inline int Max(int a,int b){ return a>b?a:b; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ scanf("%d",&a[i][j]); sum[i][j]=sum[i-1][j]+a[i][j]; } for(int i=1;i<=n;i++) for(int j=i;j<=n;j++){ for(int k=1;k<=n;k++) b[k]=sum[j][k]-sum[i-1][k]; for(int k=1;k<=n;k++){ f[k]=Max(f[k-1]+b[k],b[k]); maxx=Max(maxx,f[k]); } } printf("%d",maxx); return 0; }