您的位置:首页 > 其它

POJ 2479 初步线性 DP

2013-08-15 09:34 295 查看
//Maximum sum//
//题目链接:http://poj.org/problem?id=2479

/*
DP思想:
题目是要求一个序列的最大的两个不想交的子段和。既然要求两个子段的和想加是最大的,那么显然,两个子段和在相加之前都应该是最大的,既然是不想交的两个
子段,那么我就枚举序列中的每一个位置,在它的左边求左边子段的和,在它的右边求右边子段的和,之后筛选出,每个位置的左边子段和的最大值和右边子段和的最大值
分别存在left right 数组里面,最后 遍历所有的位置的左右子段和最大值相加,求出最大的一个,即可得出结果。
虽然没有用到很实际的DP东西,但是DP的思想这里已经有了,问题已经符合最有子结构的性质(求每一个位置的左或右的最大子段和的时候,都要依赖之前位置所求出到的结果),而且在你求解左边子段的最大和的时候,子问题也会重叠()。满足这两个性质
用DP是最好不过的
*/

#include<stdio.h>
#include<string.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define MIN -9999999
int num[55555];
int left[55555];
int right[55555];
int main()
{
int T;
int n,i,j,k;
int sum;
while(scanf("%d",&T)!=EOF)
{
while(T--)
{
sum=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
left[1]=num[1];
for(i=2;i<=n;i++)                //子问题求解,分别求每个位置的左边的最大 字段和//
{
if(left[i-1]<0)
left[i]=num[i];
else
left[i]=left[i-1]+num[i];
}
for(i=2;i<=n;i++)
left[i]=max(left[i-1],left[i]); //此时的left[i]就是i位置左边的最大子段和。
right
=num
;
for(j=n-1;j>=1;j--)                          //同理上面,求右边的最大字段值//
{
if(right[j+1]<0)
right[j]=num[j];
else
right[j]=right[j+1]+num[j];
}
for(j=n-1;j>=1;j--)
right[j]=max(right[j+1],right[j]);
sum=MIN;
for(i=2;i<=n;i++)                                                  //枚举所有的位置的所有子段最大和相加,求出最大的给sum//
sum=max(sum,left[i-1]+right[i]);
printf("%d\n",sum);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: