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;
    }
    
  • 相关阅读:
    Linux压缩和解压缩命令(linux必学基础)
    Windows Server 2012 忘记登录密码怎么办?
    linux双网卡双网关设置
    date命令的帮助信息,使用date命令输出数字做为命名标题则不会有重复标题
    linux中history加入显示时间命令代码
    the MTS failed last time时的解决办法
    linux tar.gz zip 解压缩 压缩命令
    如果centos7添加新网卡,系统不识别的解决办法
    Linux常用命令英文全称与中文解释 (pwd、su、df、du等)
    使用动态规划算法解释硬币找零问题
  • 原文地址:https://www.cnblogs.com/000zwx000/p/12467968.html
Copyright © 2011-2022 走看看