【C++/DP动态规划】最大子段和[连续]

409 阅读2分钟

题目描述

给出一个长度为 nn 的序列 aa,选出其中连续且非空的一段使得这段和最大。

输入格式

第一行是一个整数,表示序列的长度 nn。

第二行有 nn 个整数,第 ii 个整数表示序列的第 ii 个数字 a_iai​。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1

7
2 -4 3 -1 2 -4 3

输出 #1

4

说明/提示

样例 1 解释

选取 [3, 5][3,5] 子段 {3, -1, 2}{3,−1,2},其和为 44。

数据规模与约定

image.png

思路

经典的DP动态规划题目(好像也能暴力求解),定义一个数组dp,dp数组的含义为记录以第i个数结尾的前面子串中最大的字段和。可得状态转移方程为:

dp[i]=max(dp[i-1]+num[i],num[i]);

dp[i-1]为以第i-1个数结尾的最大子段和,而dp[i-1]+num[i]的含义为前面的子段和加上当前位置的值,将之与num[i]取最大值是因为如果前面的字段和加上当前的值并不比当前的值大,那我就不需要加了呗,就取当前的值。但需要注意的是,动态规划的模板写完后dp[n]并不一定存的是最大子段和,因为若dp[i]的值为负数,则dp[i+1]的值就是num[i],而num[i]的值不一定比前面的最大字段和数大。所以每次得出dp[i]还要跟前面求出的最大值比较。

AC代码

#include <bits/stdc++.h>
#include <iostream>
using namespace std;

int main()
{
    int n;
    cin>>n;
    vector<int> num,dp;
    num.resize(n+1);
    dp.resize(200005);
    for(int i=1;i<=n;i++)
        cin>>num[i];
    dp[1]=num[1];
    int sum=dp[1];
    for(int i=2;i<=n;i++)
    {
        dp[i]=max(dp[i-1]+num[i],num[i]);//状态转移方程
        sum=max(dp[i],sum);//和前面最大的比较
    }
    cout<<sum<<endl;
    return 0;
}

//2022.4.13 DP动态规划