题目描述
给n个数,要求从这n个数中找出两个区间(不能有重叠),使这两个区间的区间和之和最大。输出最大值
输入样例
1
10
1 -1 2 2 3 -3 4 -4 5 -5
输出样例
13 (前7个数一组,倒数第二个5一组)
解题思路
这题O(n^2)会T,只能考虑O(n)的算法。核心还是最大区间和的dp
(dp[i]表示以第i个数结尾的区间最大和 状态转移方程:dp[i] = max(dp[i-1]+s[i],s[i]) )
正着dp一遍,还要反着dp一遍。
On解法的核心是再开一个ans数组,ans[i]表示到第i个数为止的最大区间和(不一定以第i个数结尾,即ans[i] = max(dp[1],dp[2],……,dp[i]) 同样的,反着也要有一个ans数组。
这样,到最后只需要扫一遍,看两个ans数组之和的最大值就行了。
详见代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
#define ll long long
#define INF 1000000000
int gcd(int a,int b){return b==0? a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
const int maxn = 100010;
int s[maxn];
int dp1[maxn];
int dp2[maxn];
int ans1[maxn];
int ans2[maxn];
int main()
{
int n;
while(scanf("%d",&n) && n){
for(int i = 1 ; i <= n ; i ++) scanf("%d",&s[i]);
dp1[1] = s[1];
for(int i = 2 ; i <= n ; i ++) dp1[i] = max(s[i],dp1[i-1]+s[i]);
int _max = dp1[1];
for(int i = 1 ; i <= n ; i ++){
if(dp1[i] > _max) _max = dp1[i];
ans1[i] = _max;
}
dp2[n] = s[n];
for(int i = n-1 ; i >= 1 ; i --) dp2[i] = max(s[i],dp2[i+1]+s[i]);
_max = dp2[n];
for(int i = n ; i >= 1 ; i --){
if(dp2[i] > _max) _max = dp2[i];
ans2[i] = _max;
}
_max = -INF;
for(int i = 1 ; i <= n-1 ; i ++){//1到i i+1到n
if(ans1[i]+ans2[i+1] > _max) _max = ans1[i]+ans2[i+1];
}
printf("%d\n",_max);
}
return 0;
}
本文介绍了一个最大区间和问题的高效解法,通过O(n)算法实现。该算法使用动态规划方法,包括正向和反向DP,寻找数组中不重叠的两个子数组,使其和最大。
1079

被折叠的 条评论
为什么被折叠?



