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一模一样

转载于:https://www.cnblogs.com/ya-cpp/p/4661837.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值