最大子段和,最大子矩陣和

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;
}
相關文章
相關標籤/搜索