Poj2479 & Poj 2593

就是按着DP的思路来做的,结果还是想不到。T_T,行了,别玻璃心了,继续。

这道题目是求在一列数里,由两部分子段和组成的最大和。即对于连续整数组成的串 S1、S2,使 S1 + S2 的和最大。

题目与求最大子段和有相似之处,可以说是最大子段和的变形。

最大子段和:

  在一列数里,对于连续整数组成的串S,使 S 的值最大。

  最大子段和的动态规划方程, dp[i] = max(dp[i-1] + arr[i], arr[i]); 意义:当遍历到当前第 i 个数时,比较 {前一状态dp[i-1] 加上当前数 arr[i]}{arr[i]的大小},选取大的为当前状态。 其实 也就是看 dp[i-1] 是否大于0。

回到这个题目,我们进行的操作是,先从 0 -> n-1 算一次最大子段和,记录在 lft[] 中; 然后再从 n-1 -> 0 倒着算一次最大子段和,记录在rht[]中。

我们要再从 0 -> n-1 遍历一遍看,在当前状态 i 为基准的情况,将它的前半段 和 后半段的值加起来,然后在这里边找最大。

因为在求最大 Max 时, 前半段一定,可以直接用lft[],而后半段是到当前后半段里的最大值,所以还要进行一次操作找出每个位置之后最大值。

动态规划路还很长啊!

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 using namespace std;
 5 const int MAXN = 500100;
 6 int lft[MAXN];
 7 int rht[MAXN];
 8 int arr[MAXN];
 9 
10 int main() {
11       int T;
12       scanf("%d", &T);
13       while(T--) {
14             int n;
15             scanf("%d", &n);
16             for(int i = 0; i < n; ++i)
17                   scanf("%d", arr+i);
18             lft[0] = arr[0], rht[n-1] = arr[n-1];
19             for(int i = 1; i < n; ++i) //求到 i 的位置时, 最大子段和
20                   lft[i] = max(arr[i], lft[i-1] + arr[i]);
21             for(int i = n-2; i >= 0; --i) // 反过来求到 i 的位置时,最大子段和
22                   rht[i] = max(arr[i], rht[i+1] + arr[i]);
23             for(int i = n-2; i >= 0; --i) // 在计算两部分相加的时候,后边是从当前到最后所有最短和最大的
24                   rht[i] = max(rht[i+1], rht[i]);
25             int Max = -1000000;
26             for(int i = 0; i < n-1; ++i) //计算由两部分组成的子段和里的最大值
27                   Max = max(Max, lft[i] + rht[i+1]);
28             printf("%d\n", Max);
29       }
30       return 0;
31 }

 2593与2479一模一样

posted @ 2015-07-20 16:36  unicoe  阅读(191)  评论(0编辑  收藏  举报