分治法 && 動態規劃 洛谷P1115 最大子段和

7丨發表於2020-12-06

題目

P1115 最大子段和
在這裡插入圖片描述

本題可採用兩種方法

一、分治法(時間複雜度:logn)

*分治法可以通俗的解釋為:把一片領土分解,分解為若干塊小部分,然後一塊塊地佔領征服,被分解的可以是不同的政治派別或是其他什麼,然後讓他們彼此異化。

*分治法使用場景

該問題的規模縮小到一定的程度就可以容易的解決。該問題可以分解為若干個規模較小的相同問題,即該問題具有最優子結構性質。 利用該問題分解出的子問題的解可以合併為該問題的解。 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子問題

*分解:將原問題分解為若干個規模較小,相互獨立,與原問題形式相同的子問題
解決:若子問題規模較小而容易被解決則直接解,否則遞迴地解各個子問題
合併:將各個子問題的解合併為原問題的解
簡單來說: 當你發現原問題可以分成幾個小問題,小問題與大問題可以用同一個遞迴函式解決。且跨越兩個小問題之間的問題也可以求解。那麼就可以考慮用分治法。 分治法通常可以將複雜度降到logn。

將區間分為兩半。遞迴的處理左右區間。橫跨中間的部分,可以求左區間最大字尾和+右區間最大字首和來求解。 最終答案為max(左區間,右區間,橫跨兩個區間)的最大子段和。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
#define inf 0x3f3f3f3f
int a[N],n;
int solve(int l,int r)
{
	if(l>=r)return a[l];
	int mid=(l+r)/2;
	int res=max(solve(l,mid),solve(mid+1,r));
	int maxl=-inf,maxr=-inf,sum=0;
	for(int i=mid;i>=l;i--)
	{
		sum+=a[i];
		maxl=max(maxl,sum);
	}
	sum=0;
	for(int i=mid+1;i<=r;i++)
	{
		sum+=a[i];
		maxr=max(maxr,sum);
	}
	return max(maxl+maxr,res);
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	cout<<solve(1,n);
	return 0;
}

二、動態規劃 (時間複雜度:n)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10, inf=0x3f3f3f3f3f;
int f[N];
int main(){
	int n;
	cin>>n;
	int ans=-inf;
	for(int i=1; i<=n;i++){
		int x;
		cin>>x;
		f[i]=max(f[i-1]+x,x);
		ans=max(ans,f[i]); 
	}
	cout<<ans;
	return 0;
} 

相關文章