(DP)51NOD 1049&1050 (循环)最大子段和

N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值。当所给的整数均为负数时和为0。
 
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
Output
输出最大子段和。
Input示例
6
-2
11
-4
13
-5
-2
Output示例
20
解:简单的dp问题,但其实这道题不需要开数组。
 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     int n;
 6     while (scanf_s("%d", &n) != EOF)
 7     {
 8         long long max = 0,dp = 0;
 9         for (int i = 0, temp; i < n; i++)
10         {
11             scanf_s("%d", &temp);
12             dp = dp + temp > 0 ? dp + temp : 0;
13             max = max > dp ? max : dp;
14         }
15         printf("%lld\n", max);
16     }
17     return 0;
18 }

 拓展问题是将数组的首尾相连后求最大字串

答题思路其实差不多

主要考虑两种情况:

1.最大串不在首尾相连处(上述代码即可求得)

2.最大串在首尾相连处(则数组最小串即为剩余子项和,不在首尾相连处。可用稍加更改上述代码求得最小串,然后最大串=总和-最小串)

对上述做法的两个答案比较即可。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 
 6 int main()
 7 {
 8     int n;
 9     while (scanf_s("%d", &n) != EOF)
10     {
11         int a;
12         long long min = 0, max = 0, sum = 0, dpn = 0, dpx = 0;
13         for (int i = 1; i <= n; i++)
14         {
15             scanf_s("%d", &a);
16             sum += a;
17             if (dpx + a < 0) dpx = 0;
18             else dpx = dpx + a;
19             max = dpx > max ? dpx : max;
20             if (dpn + a > 0) dpn = 0;
21             else dpn = dpn + a;
22             min = dpn < min ? dpn : min;
23         }
24         max = max > sum - min ? max : sum - min;
25         printf("%lld\n", max);
26     }
27     return 0;
28 }

 

posted @ 2018-09-11 17:10  Ekalos  阅读(191)  评论(0编辑  收藏  举报