最大子段和,最大子矩阵和

1定义

最大子段和是指,对于一段数列来讲,有区间\([l,r]\)使得\(a_i+a_{i+1}+...a_r\)最大,这个最大的和被称为最大子段和。php

扩展内容是求解最大子矩阵和。ios

2算法

2.1 朴素算法

经过枚举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)\)数组

2.2优化

咱们能够发现,其实在计算若干个数的和时,有重复计算,咱们能够提早预处理前缀和来避免这个问题,优化时间复杂度。优化

代码: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

2.3 DP

这个问题能够经过动态规划来解决。get

咱们发现,若是在咱们已经知道以i结尾的最大子段和,那么下一步的决策只有两个:string

  1. 咱们把第i+1个数接在后面。
  2. 咱们让第i+1个数本身成为一个序列。

咱们设\(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;
}
相关文章
相关标签/搜索