POJ_2479与POJ_2593 Maximum Sum

本文介绍了一种使用双向动态规划解决最大子序列和问题的方法,包括原始计算、单向动态规划及双向动态规划三种方式,并提供了POJ2479和POJ2593的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

POJ 2479:http://poj.org/problem?id=2479

POJ 2593:http://poj.org/problem?id=2593

分类:动态规划

算法:两道题目除了输入格式不同以外,其它算法一样,利用双向动态规划算法。

(1)最原始的计算方法

设有数组长度为,用一个的矩阵进行和的存储,即

则计算的时间复杂度为:

接下来,需要求出不相交的两段和的最大值

为数组的分界,则第一段是,第二段是的取值范围为,因此计算最大值的过程中,需要比较的次数为:

因此计算步骤为

因此渐进时间复杂度为

(2)利用单向动态规划算法

如果原题中是求一段连续子序列的和,即

因此可以利用动态规划算法(最优子结构的证明可以找一本算法书看一下):

表示为到第个元素为止的连续子序列的最大值和,其具有如下的最优子结构:

因此当求两段和时,首先通过分界标识将数组分为两部分,的取值范围为,再根据上述的最优子结构公式计算出第二段的最大值,再求和,最终结果即为

其中,为从第项开始利用动态规划计算的最大值。上式实质上的比较次数为一个二重循环,即为

因此渐进时间复杂度为

(3)利用双向动态规划算法

由于是求不相交的两段连续子序列和的最大值,因此造成上述第(2)种算法耗时的主要原因在于需要用遍历的方法逐个比较最大值,因此需要双重循环。为了解决上述问题,从左至右以及从右至左分别采用动态规划,并且对函数进行改进,其保存的不是至第个元素的最大值,而是小于或等于第个元素的最大值,在如下的程序中,用MAX变量进行赋值。因此最终仅需要执行单层循环3次,因此渐进时间复杂度为

后续工作的思考:需要对最优子结构进行数学证明。

POJ 2479 C++ 源码

 1 #include<cstdio>
 2 
 3 using namespace std;
 4 
 5 int A[100001] = {0};       // 初始化数组
 6 int d1[100001] = {0};        // 状态方程,用于保存当前最大值
 7 int d2[100001] = {0};
 8 
 9 int solve(int n);
10 
11 int main()
12 {
13     int T,n;
14     scanf("%d",&T);
15     for (int j = 0; j < T; j++)
16     {
17         scanf("%d",&n);
18         for (int i = 0; i < n; i++)
19             scanf("%d",&A[i]);
20         printf("%d\n",solve(n));
21     }
22     return 0;
23 }
24 
25 
26 int solve(int n)
27 {
28     // O(n)
29     int current = A[0];
30     d1[0] = A[0];
31     int MAX = A[0];
32     for (int i = 1; i < n; i++)
33     {
34         if (current+A[i] >= A[i]) current = current + A[i];
35         else current = A[i];
36         if (current <= MAX) d1[i] = MAX;
37         else
38         {
39             MAX = current;
40             d1[i] = MAX;
41         }
42     }
43     // O(n)
44     MAX = A[n-1];
45     current = A[n-1];
46     d2[n-1] = A[n-1];
47     for (int i = n-2; i >= 0; i--)
48     {
49         if (current+A[i] >= A[i]) current = current + A[i];
50         else current = A[i];
51         if (current <= MAX) d2[i] = MAX;
52         else
53         {
54             MAX = current;
55             d2[i] = MAX;
56         }
57     }
58     int result = d1[0] + d2[1];
59 
60     for (int i=1; i < n-1; i++)
61     {
62         if (d1[i] + d2[i+1] > result)
63             result = d1[i] + d2[i+1];
64     }
65     return result;
66 }

POJ 2593 C++ 源码

 1 #include<cstdio>
 2 #include<iostream>
 3 
 4 using namespace std;
 5 
 6 int A[100001] = {0};       // 初始化数组
 7 int d1[100001] = {0};        // 状态方程,用于保存当前最大值
 8 int d2[100001] = {0};
 9 
10 int solve(int n);
11 
12 int main()
13 {
14     int n;
15     while (scanf("%d",&n) && n!=0)
16     {
17         for (int i = 0; i < n; i++)
18             scanf("%d",&A[i]);
19         printf("%d\n",solve(n));
20     }
21     return 0;
22 }
23 
24 
25 int solve(int n)
26 {
27     // O(n)
28     int current = A[0];
29     d1[0] = A[0];
30     int MAX = A[0];
31     for (int i = 1; i < n; i++)
32     {
33         if (current+A[i] >= A[i]) current = current + A[i];
34         else current = A[i];
35         if (current <= MAX) d1[i] = MAX;
36         else
37         {
38             MAX = current;
39             d1[i] = MAX;
40         }
41     }
42     // O(n)
43     MAX = A[n-1];
44     current = A[n-1];
45     d2[n-1] = A[n-1];
46     for (int i = n-2; i >= 0; i--)
47     {
48         if (current+A[i] >= A[i]) current = current + A[i];
49         else current = A[i];
50         if (current <= MAX) d2[i] = MAX;
51         else
52         {
53             MAX = current;
54             d2[i] = MAX;
55         }
56     }
57     int result = d1[0] + d2[1];
58 
59     for (int i=1; i < n-1; i++)
60     {
61         if (d1[i] + d2[i+1] > result)
62             result = d1[i] + d2[i+1];
63     }
64     return result;
65 }

 

转载于:https://www.cnblogs.com/caoxiao18m/archive/2012/12/04/2800040.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值