暴力+分治+贪心+DP:最大子序列和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

暴力:暴力列举所有可能的连续子数组,算法复杂度O(N^3)算法1:
 1 int MaxSubseqSum1(int A[], int N)
 2 {
 3     int ThisSum, MaxSum = 0;
 4     int i,j,k;
 5
 6     for (i = 0; i < N; i++)  //i对应子列左端位置
 7     {
 8         for (j = i; j < N; j++)  //j对应子列右端位置
 9         {
10             ThisSum = 0;
11             for (k = i; k <= j; k++) //一段子列的和
12             {
13                 ThisSum += A[k];
14             }
15             if(ThisSum > MaxSum)
16                 MaxSum = ThisSum; //更新
17         }
18     }
19     return MaxSum;
20 }
每次从i加到j,我们都必须要经历k循环,i+(i+1)...j,所以每次j循环后都要经历一个k循环从i加到j,想想完全没有必要,可以直接在前一个子序列的基础上加一个元素,所以k循环是没有必要的。因此优化算法在相同的i不同的j只需要在j-1次的循环的基础上累加一项即可,算法复杂度更新为O(N^2)算法2:

 1 int MaxSubseqSum2(int A[], int N)
 2 {
 3     int ThisSum, MaxSum = 0;
 4     int i,j,k;
 5
 6     for (i = 0; i < N; i++)  //i对应子列左端位置
 7     {
 8         ThisSum = 0;
 9         for (j = i; j < N; j++)  //j对应子列右端位置
10         {
11             ThisSum += A[k];  //在上一个子序列和的基础上加一个数
12
13             if(ThisSum > MaxSum)
14                 MaxSum = ThisSum;
15         }
16     }
17     return MaxSum;
18 }

算法3:分治把大问题拆成小问题,然后逐个解决,最后合并起来。

把数组一分为二,分别递归(即左右两边再分成小的左右两边)的去解决左右两边问题,得到两边的最大子列和,还有一种情况跨越边界的最大子列和,然后想要的结果就是这三个数之间的最大的那个数。算法复杂度O(NlogN)

 1 int Max3( int A, int B, int C )
 2 { /* 返回3个整数中的最大值 */
 3     return A > B ? A > C ? A : C : B > C ? B : C;
 4 }
 5
 6 int DivideAndConquer( int List[], int left, int right )
 7 { /* 分治法求List[left]到List[right]的最大子列和 */
 8     int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */
 9     int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/
10
11     int LeftBorderSum, RightBorderSum;
12     int center, i;
13
14     if( left == right )  { /* 递归的终止条件,子列只有1个数字 */
15         if( List[left] > 0 )  return List[left];
16         else return 0;
17     }
18
19     /* 下面是"分"的过程 */
20     center = ( left + right ) / 2; /* 找到中分点 */
21     /* 递归求得两边子列的最大和 */
22     MaxLeftSum = DivideAndConquer( List, left, center );
23     MaxRightSum = DivideAndConquer( List, center+1, right );
24
25     /* 下面求跨分界线的最大子列和 */
26     MaxLeftBorderSum = 0; LeftBorderSum = 0;
27     for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */
28         LeftBorderSum += List[i];
29         if( LeftBorderSum > MaxLeftBorderSum )
30             MaxLeftBorderSum = LeftBorderSum;
31     } /* 左边扫描结束 */
32
33     MaxRightBorderSum = 0; RightBorderSum = 0;
34     for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */
35         RightBorderSum += List[i];
36         if( RightBorderSum > MaxRightBorderSum )
37             MaxRightBorderSum = RightBorderSum;
38     } /* 右边扫描结束 */
39
40     /* 下面返回"治"的结果 */
41     return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
42 }
43
44 int MaxSubseqSum3( int List[], int N )
45 { /* 保持与前2种算法相同的函数接口 */
46     return DivideAndConquer( List, 0, N-1 );
47 }

算法4:贪心算法(在线处理算法)

每输入一个数据,进行即时处理,在任何一个地方停止输入,算法都能得到正确的解,即总是做出在当前看来最好的选择。

只需遍历一遍数组,算法复杂度为O(N)。

 1 int MaxSubseqSum4(int A[], int N)
 2 {
 3     int i;
 4     int ThisSum, MaxSum;
 5     ThisSum = MaxSum = 0;
 6
 7     for (i = 0; i < N; i++)  //向右累加
 8     {
 9         ThisSum += A[i];
10         if (ThisSum > MaxSum)
11             MaxSum = ThisSum;  //发现更大则更新
12         else if (ThisSum > MaxSum) //如果当前子序列为负,因为它不能使后边子列和增大
13             ThisSum = 0; //直接放弃累加
14     }
15     return MaxSum;
16 }

算法5:动态规划(DP)

不断更新dp[i]中的值,表示A数组中以A[i]为结尾的最大子序列和,例如A = [2,3,-6,2,4],则dp = [2,5,-1,2,6],则dp数组中的最大值就是最大子序列和就是6.

只需要遍历一遍数组,算法复杂度O(N)

 1 int MaxSubseqSum1(int A[], int N)
 2 {
 3     int i;
 4     int dp[N];
 5     int ThisSum = 0;
 6     dp[0] = A[0];
 7     for (i = 1; i < N; i++)
 8     {
 9         if (dp[i]<0 || (i==1 && dp[0]<0)) //如果A[0]就小于0则它并不能使后边序列增大所以不累加,或者后边的子序列和中出现负值
10         {
11             dp[i] = A[i];
12         }
13         else
14         {
15             dp[i] = dp[i - 1] + A[i];
16         }
17     }
18
19     return Max.dp[i];
20 }

DP是根据自己的理解写的,如有不对,请指正谢谢。





原文地址:https://www.cnblogs.com/ZhengLijie/p/12533763.html

时间: 2024-11-14 11:59:10

暴力+分治+贪心+DP:最大子序列和的相关文章

URAL 1203 Scientific Conference(贪心 || DP)

Scientific Conference 之前一直在刷计算几何,邀请赛连计算几何的毛都买见着,暑假这一段时间就做多校,补多校的题目,刷一下一直薄弱的DP.多校如果有计算几何一定要干掉-.- 题意:给你N个报告会的开始时间跟结束时间,问你做多可以听几场报告会.要求报告会之间至少间隔为1. 思路:其实是个活动安排问题,可以用贪心也可以用DP,贪心写起来会比较简单一些,因为练习DP,所以又用DP写了一遍. 贪心的话就是一个很简单的活动选择问题,从结束时间入手,找每次的最优选择. 1 struct n

codeforces349B - Color the Fence 贪心+DP

题意:1-9每个字母需要消耗ai升油漆,问你用油漆最多刻意画多大的数字 解题思路: 首先我们要贪心,可以知道我最优是先使我们位数尽可能长,然后才是就是位数长的情况下使得从最高位开始尽可能大.所以要取满足最长位最小的那个数,方便我们DP 解题代码: 1 // File Name: 349b.cpp 2 // Author: darkdream 3 // Created Time: 2014年07月24日 星期四 21时40分13秒 4 5 #include<vector> 6 #include&

HDU - 2089 不要62 (暴力或数位DP)

Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众. 不吉利的数字为所有含有4或62的号码.例如: 62315 73418 88914 都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列. 你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新

挖坑#3-----DP优化+CDQ分治+期望DP

1492: [NOI2007]货币兑换Cash 1176: [Balkan2007]Mokia 1452: [JSOI2009]Count 1563: [NOI2009]诗人小G tyvj1309  刷题的玖君 3036: 绿豆蛙的归宿 1076: [SCOI2008]奖励关 1415: [Noi2005]聪聪和可可 1444: [Jsoi2009]有趣的游戏 2337: [HNOI2011]XOR和路径 3586: 字符串生成器 记得还有的啊... 挖坑#3-----DP优化+CDQ分治+期望

HDU 4939 Stupid Tower Defense(贪心+dp)

HDU Stupid Tower Defense 题目链接 题意:有一些塔,红塔能攻击经过他的,绿塔能攻击经过之后的,蓝塔能把经过之后的减速,求在1-n上放塔,求伤害最大值 思路:一开始以为直接贪心,绿塔最前,蓝塔中间,红塔最后就可以了,结果其实是错的 不过,红塔放最后是肯定的,这个很显然就不多证明了,是贪心的思想 然后就dp[i][j]表示放到i,前面有j个绿塔去状态转移即可 代码: #include <cstdio> #include <cstring> #include &l

CF459E Pashmak and Graph【贪心+dp】

题目:CF459E Pashmak and Graph 题意:给出n个点,m条边的图,然后让你每次只能向权值更大边走,求最大的边数.可以走多次 分析:由于点比较多,我们可以先对权值从小到大排序,然后从小的开始,更新它的到的节点的值为前一个节点值+1,但是还会出现权值相等成环的情况,所以我们可以对相等的先不更新,保存起来,等相等的结束了再更新. 代码: #include<cstdio> #include<algorithm> using namespace std; const in

【bzoj1495】[NOI2006]网络收费 暴力+树形背包dp

题目描述 给出一个有 $2^n$ 个叶子节点的完全二叉树.每个叶子节点可以选择黑白两种颜色. 对于每个非叶子节点左子树中的叶子节点 $i$ 和右子树中的叶子节点 $j$ :如果 $i$ 和 $j$ 的颜色都为当前节点子树中颜色较多(相等视为白色)的那个,则不需要付出代价:都为较小的那个则需要付 $2f[i][j]$ 的代价:否则需要付 $f[i][j]$ . 求最小代价. 输入 输入文件中第一行有一个正整数N. 第二行有2N个整数,依次表示1号,2号,…,2N号用户注册时的付费方式,每一个数字若

贪心+dp

贪心+dp 好多题都是这个思想, 可以说是非常重要了 思想一: 在不确定序列无法dp的情况下, 我们不妨先假设序列已经选定, 而利用贪心使序列达到最优解, 从而先进行贪心排序, 在进行dp选出序列 思想二: 最优解一定满足上一个状态在某 Problem 1 n 座楼房,立于城中. 第 i 座楼,高度 \(h_i\) . 你需要一开始选择一座楼,开始跳楼.在第 座楼准备跳楼需要 的花费.每次可以跳到任何一个还没有跳过的楼上去.但跳楼是有代价的,每次跳到另外一座楼的代价是两座楼高度的差的绝对值,最后

HDU-1257 最少拦截系统 贪心/DP 最长上升子序列的长度==最长不上升子序列的个数?

题目链接:https://cn.vjudge.net/problem/HDU-1257 题意 中文题咯中文题咯 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少