POJ 2479 最大子段和 解题心得

本文介绍了一种高效算法,用于找出一串整数中两个连续子串的最大和,通过动态规划思想实现O(n)时间复杂度。文章详细解释了解决方案的思路和步骤,并提供了完整的C++代码实现。

问题描述:

         给一串整数下标从1~n,找出两个子串(每个子串中的下标连续),下标分

别为s1~t1和s2~t2,其中1<=s1<=t2<s2<=t2<=n,问子串和最大为多少?

 

引:

求一串数中一个连续子串和最大值的DP解法为:

设原数组为a[]

令b[j]为以第j个元素结尾的字串和的最大值。只有两种情况:1.只有a[j]  2.a[j]

接在以a[j-1]结尾的字串后面

对于情况二的证明,可用反证法证明得,以a[j-1]结尾的子串和必为该状态的最大值

所以b[j]=max{a[j],b[j-1]+a[j]}   

这样便求出了以每个元素结尾的字串和最大值,由于实际最大值字串必为其中之一,

再遍历一遍取其中最大值即可。

 

思路:

有了上述求一个子串最大值的解法,再推到求两个字串最大值的方法就很自然了。只

要从a[0]开始,依次取a[0],a[1].....为划分元素,

即s1<=t1<=a[x]<s2<=t2,并分别求最大值,并再这些最大值中再找最大值

证明如下,假设实际最优划分为s1,t1,s2,t2,t1<s2,可取划分元素为t1,则该最大值

必和以t1为划分元素时两边的最大值的和相等,否则矛盾。因此最优解必为n种划分

情况中的一种的最优解。

问题现在转化为,如何找到每种划分的最大值?其实只要分找两边字串各自的最大字

串和即可(反证法)

 

解法:

1.从头到尾遍历一遍,求出leftsum[x]

2.从尾到头遍历一遍,求出rightsum[x]

3.从头到尾遍历一遍,求出最大的和

 

步骤一和二中,要用中间变量b记录中间值。以步骤1为例,要先用b记录以a[i](设

划分元素为a[i])结尾的最大字串和,再与leftsum[i-1]比较,即比较包括a[i]和不

包括a[i]的字串,找出最大值,即为a[0]~a[i]的所有字串的最大值。步骤二同理。

 

这个算法耗时O(n),是比较快的算法。我刚开始做的时候用了比较笨的方法,就是把

求一个字串最大和做成一个函数,再遍历数组同时调用这个函数来算leftsum和

rightsum。这样需耗时O(n2),因为调用一次函数的代价为O(n),结果超时了。。。

 

这题还有个小陷阱,就是这个最大和可能是负值,考虑全是负数的情况,但即便如此

算法最多只会算两个负数相加,题目中条件说元素的绝对值<=10000,因此sum的初始

值可赋-20000,保险起见可赋-60000,ok,这下可以AC了~~~

 

源代码如下:

#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
 int T;
 cin>>T;
 int t,i,k;
 for(t=0;t<T;t++)  {
  int n,sum=-60000,b;  //注意sum可能小于0!!!(全是负数,但此时最多为两

个负数的和)
  cin>>n;
  int *a=new int[n];
  int *lsum=new int[n];
  int *rsum=new int[n];
  for(i=0;i<=n-1;i++)
   scanf("%d",&a[i]);
  lsum[0]=a[0];
  rsum[n-1]=a[n-1];
  b=a[0];
  for(k=1;k<=n-1;k++) {
   if(b>0) b+=a[k];
   else b=a[k];
   if(b>lsum[k-1]) lsum[k]=b;
   else  lsum[k]=lsum[k-1];
  }
  b=a[n-1];
  for(k=n-2;k>=0;k--) {
   if(b>0)   b+=a[k];
   else b=a[k];
   if(b>rsum[k+1]) rsum[k]=b;
   else rsum[k]=rsum[k+1];
  }
  for(k=0;k<=n-2;k++)
   if(lsum[k]+rsum[k+1]>sum) sum=lsum[k]+rsum[k+1];
  delete[] a;
  delete[] lsum;
  delete[] rsum;
  cout<<sum<<endl;
 }
 return 0;
}

 

PS:最好养成new过delete的习惯,我比较了下,一个耗内存800+K,一个12000+K,数据

再多些就要爆内存了。。

还有输入比较多时用scanf划算,省时呵呵。

 

 

 

 

 

 

### POJ 2479 题目分析 POJ 2479 是一道经典的算法题目,通常涉及动态规划 (Dynamic Programming, DP) 或其他优化方法来解决复杂问题。虽然具体题目的描述未提供,但从常见的 POJ 平台上的题目来看,这类编号的题目往往围绕资源分配、路径规划或其他组合优化场景展开。 #### 动态规划解决方案概述 动态规划是一种通过分解问题并存储中间结果以减少重复计算的方法。对于某些特定类型的最优化问题,DP 提供了一种高效且优雅的解法。例如,在背包问题或序列匹配等问题中,动态规划能够显著降低时间复杂度[^1]。 以下是基于假设的一个通用动态规划框架用于解决类似问题: ```python def dp_solution(items, capacity): n = len(items) # 初始化二维数组表示状态转移矩阵 dp = [[0 for _ in range(capacity + 1)] for __ in range(n + 1)] for i in range(1, n + 1): # 遍历物品 weight, value = items[i - 1] for j in range(capacity + 1): # 遍历容量 if j >= weight: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value) else: dp[i][j] = dp[i - 1][j] return dp[n][capacity] ``` 此代码片展示了如何构建一个简单的动态规划表以处理具有重量价值属性的项目集合,并找到不超过给定容量的最大总价值。 #### 差分约束系统的应用 如果该问题是关于不等式的满足条件,则可以考虑采用差分约束系统进行建模。这种方法的核心思想是将一系列线性不等式转化为图论中的单源最短路径或者最长路径问题。特别地,当涉及到绝对差异限制时,可以通过引入虚拟节点连接实际变量形成网络结构,随后运行 SPFA 算法检测是否存在负权回路或正权回路来验证可行性[^3]。 需要注意的是,为了保证整个图形连通以便于正确执行上述过程,应当增加一个超级起点向所有其它顶点发出零权重边。 #### 推荐学习路线 针对希望深入理解这些高级技巧的学习者,《POJ 刷题顺序》一文中给出了详尽指导,涵盖了从基础到高阶的不同层次练习建议[^4]。遵循这样的计划可以帮助逐步掌握各类经典模型及其变体的应用场合。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值