一、文章来由
晚上一水~~poj2479,一道简单的dp问题,回顾一下动态规划
二、求最大子段和
这道题是求一个序列中的两个子段的最大和,是求纯的最大和的一个变体,例如题目中给出的例子
1 -1 2 2 3 -3 4 -4 5 -5
In the sample, we choose {2,2,3,-3,4} and {5}, then we can get the answer.
答案是 13
如何求一个序列的子段和:
int MaxSub (int a[],int N)//此为只需要求最大的和,时间复杂度是O(n)
{
int *dp = new int(N);
int max, i;
max = dp[0] = a[0];
for (i=1; i<N; i++)
{
if (dp[i-1] > 0)
dp[i] = dp[i-1] + a[i];
else
dp[i] = a[i];
if (dp[i] > max)
max = dp[i];
}
delete dp;
return max;
}
AI 代码解读
分析:
思路很清晰的写法,每次都判断,当前dp值(即子串当前最大值),如例子中的:
1 -1 2 2 3 -3 4 -4 5 -5
1 0 2 4 7 4 8 4 9 4
这样就很清楚了~~
三、解题报告
先上AC代码:
#include <iostream>
#include <limits>
using namespace std;
#define MAXN 50002
int map[MAXN];
int Ldp[MAXN];
int Rdp[MAXN];
void MaxLSub (int a[],int N)//此为只需要求最大的和,时间复杂度是O(n)
{
int i;
Ldp[0] = a[0];
for (i=1; i<N; i++)
{
if (Ldp[i-1] > 0)
Ldp[i] = Ldp[i-1] + a[i];
else
Ldp[i] = a[i];
}
for(i=1; i<N; i++)
Ldp[i] = Ldp[i]<Ldp[i-1]?Ldp[i-1]:Ldp[i];
}
void MaxRSub (int a[],int N)//此为只需要求最大的和,时间复杂度是O(n)
{
int i;
Rdp[N-1] = a[N-1];
for (i=N-2; i>-1; i--)
{
if(Rdp[i+1]>0)
Rdp[i] = Rdp[i+1]+a[i];
else
Rdp[i] = a[i];
}
for (i=N-2; i>-1; i--)
Rdp[i] = Rdp[i]<Rdp[i+1]?Rdp[i+1]:Rdp[i];
}
int main()
{
int T,n;
cin>>T;
while (T--)
{
scanf("%d",&n);
//cin>>n;
for (int i=0;i<n;++i)
{
scanf("%d",&map[i]);
//cin>>map[i];
}
MaxLSub(map,n); //生成dp
MaxRSub(map,n);
int res=INT_MIN;
for (int i=1;i<=n-1;++i)
{
int tmp = Ldp[i-1]+Rdp[i];
res = tmp>res?tmp:res;
}
cout<<res<<endl;
}
return 0;
}
AI 代码解读
但是这题用暴力的 MaxSub(map,i)+MaxSub(map+i,n-i) 去做,是没有用的,会TLE,后来我将cin换成scanf,也是不行的,再后来用了这个方法:
int findMax(int lb,int rb)
{
int max=INT_MIN;
for (int i=lb;i<=rb;++i)
{
max = dp[i]>max?dp[i]:max;
}
return max;
}
int main()
{
/////... ...
for (int i=1;i<=n-1;++i)
{
//int tmp = MaxSub(map,i)+MaxSub(map+i,n-i); //n^2
int tmp = findMax(0,i) + findMax(i+1,n)-dp[i-1];
res = tmp>res?tmp:res;
}
/////... ...
}
AI 代码解读
究其原因是,用 MaxSub(map,i)+MaxSub(map+i,n-i) 纯暴力方法,是 O(n^2) 的复杂度,后来改成 findMax(0,i) + findMax(i+1,n)-dp[i-1] 其实依然是 O(n^2) 的复杂度。。
AC代码是用从左往右,找出常规的最大子串,然后用
for(i=1; i<N; i++)
Ldp[i] = Ldp[i]<Ldp[i-1]?Ldp[i-1]:Ldp[i];
AI 代码解读
求出从左往右,当前点的最大值,如果用例子中的值就是:
1 -1 2 2 3 -3 4 -4 5 -5
1 0 2 4 7 4 8 4 9 4
1 1 2 4 7 7 8 8 9 9
保证从左往右,一定是变大,找到一个点就可以找到这个点左边的最大值~~
同理,可以计算从右往左的,一个点右边的最大值,这样就用空间换时间了,但是即使这样,也只跑出了438MS。。。
而且将scanf换成cout,又TLE了
—END—