zoukankan      html  css  js  c++  java
  • 算法:最大子段和问题

    最大子段和是一个学习动态规划必学的问题,也是最基础的动态规划问题。

    例题

    洛谷1115 最大子段和

    题目描述:
    给出一段序列,选出其中连续且非空的一段使得这段和最大。

    输入格式:
    第一行:是一个正整数N,表示了序列的长度。
    第二行:包含N个整数num[i],描述了这段序列。

    输出格式:
    一个整数,为最大的子段和是多少。

    输入样例:

    7
    2 -4 3 -1 2 -4 3
    

    输出样例:

    4
    

    最大子段和

    对于最大子段和这个问题,其实我们发现如果说序列中所有的数都是正数,那么最大子段和一定是所有数的和,但为什么有时候不是呢?这就是负数捣的鬼。那么怎么解决负数呢?这就要用到动态规划了,提到DP,就一定就要去想:状态、转移方程、初值和答案了。

    1. 状态:dp[i]指在a[1] ~ a[i]这i个数中,结尾必须为a[i]这个数的最大子段和。
    2. 转移方程:dp[i] = max(0, dp[i - 1]) + a[i];
      其实这个的意思就是:如果说dp[i - 1]小于0,具体些就是以a[i - 1]这个数为结尾的最大子段和小于0的话,那么还不如说就不要前面的数,只留下一个a[i]呢。反之,若dp[i - 1]大于0,那么就让dp[i] = dp[i - 1] + a[i],这样可以更大些。(PS:其实就是分两种情况讨论,看哪种情况下答案更大就是了)。
    3. 初值:dp[0] = 0;
    4. 答案:max{dp[i]},因为不同子段结尾有a[1] ~ a[n]共n种情况,取其最大值就大功告成了。

    最后算一下算法时间复杂度:只有一层循环,所以时间复杂度就是O(n)级别的了。

    代码

    # include <cstdio>
    # include <cmath>
    # include <cstring>
    # include <algorithm>
    
    using namespace std;
    
    const int N_MAX = 200000;
    
    int n;
    int a[N_MAX + 10];
    int dp[N_MAX + 10];
    
    int maxSum()
    {
    	int ans = -2e9;
    	for (int i = 1; i <= n; i++) {
    		dp[i] = max(dp[i - 1], 0) + a[i];
    		ans = max(ans, dp[i]);
    	}
    	return ans;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++)
    		scanf("%d", &a[i]);
    	printf("%d
    ", maxSum());
    	return 0;
    }
    
  • 相关阅读:
    网页布局1
    下拉菜单的制作
    状态玻璃效果菜单(实例)
    鼠标经过时整行变色
    鼠标经过时单元格变色
    Bootstrap3.0入门学习系列规划[持续更新]
    使用jQuery实现简单的拖动效果
    解决VS2012新建MVC3等项目时,收到加载程序集“NuGet.VisualStudio.Interop…”的错误
    Flash3D引擎:Away3D 4.1 Alpha版介绍
    Away3d 基础 1 ---对一个简单类的解释
  • 原文地址:https://www.cnblogs.com/000zwx000/p/12467968.html
Copyright © 2011-2022 走看看