POJ 2479 初步线性 DP

来源:互联网 发布:林冉网络班2017招生 编辑:程序博客网 时间:2024/05/17 06:40
//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 -9999999int 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];elseleft[i]=left[i-1]+num[i];}for(i=2;i<=n;i++)left[i]=max(left[i-1],left[i]); //此时的left[i]就是i位置左边的最大子段和。right[n]=num[n];for(j=n-1;j>=1;j--)                          //同理上面,求右边的最大字段值//{if(right[j+1]<0)right[j]=num[j];elseright[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;}


原创粉丝点击