dp - 循环数组的最大和

首尾相连数组的最大子数组和

时间限制:1000 ms  |  内存限制:65535 KB

难度:4

描述
给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的。数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选)。
输入
输入包含多个测试用例,每个测试用例共有两行,第一行是一个整数n(1=<n<=100000),表示数组的长度,第二行依次输入n个整数(整数绝对值不大于1000)。
输出
对于每个测试用例,请输出子数组和的最大值。
样例输入
6
1 -2 3 5 -1 2
5
6 -1 5 4 -7
样例输出
10
14

题目分析 :  首先想到的肯定是将数组扩大一倍, 将环变成链 , 但这里还有一个更巧妙的办法, 就是此题的最终结果一定是由着两种情况产生的, 一是 我不需要首尾相连,直接一个串过去就有最大值,二是我需要首尾相接,

想一想 , 它为什么需要首尾相接才有最大值? 不就是因为串的中间有一段最大 负串影响了第一种情况, 所以我可以求最大负串的和 。

代码示例:  
/*
 * Author:  ry
 * Created Time:  2017/9/19 8:09:07
 * File Name: 1.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
using namespace std;
const int eps = 2e5+5;
const double pi = acos(-1.0);
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define ll long long

int pre[eps];
int dp[eps];

int main() {
    int n;

    while(~scanf("%d", &n)){
        int sum = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d", &pre[i]);
            sum += pre[i];
        }

        memset(dp, 0, sizeof(dp));
        int ans = 0;
        for(int i = 1; i <= n; i++){
            dp[i] = max(dp[i-1]+pre[i], pre[i]);
            if (dp[i] > ans) ans = dp[i];
        }
        int ans2 = 0;
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++){
            dp[i] = min(dp[i-1]+pre[i], pre[i]);
            if (dp[i] < ans2) ans2 = dp[i];
        }
      //  if (ans > sum) printf("%d\n", sum);
         printf("%d\n", max(ans, sum-ans2));

    }

    return 0;
}

时间: 2024-10-13 12:12:01

dp - 循环数组的最大和的相关文章

lintcode循环数组之连续子数组求和

v 题目:连续子数组求和 II 给定一个整数循环数组(头尾相接),请找出一个连续的子数组,使得该子数组的和最大.输出答案时,请分别返回第一个数字和最后一个数字的值.如果多个答案,请返回其中任意一个. v 样例 给定 [3, 1, -100, -3, 4], 返回 [4,0]. v 思路 1.如果不是循环数组,求解连续子区间和的思路如下: 首先设一个累加变量和sum和最大值变量maxN,[ld, rd]表示当前正在累加的区间,[lt,rt]表示最大和的区间.从左边开始一直累加,并初始当前区间[ld

51nod 1050 循环数组最大子段和【环形DP/最大子段和/正难则反】

1050 循环数组最大子段和 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input 第1

51Nod 1050 循环数组最大子段和 | DP

Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 分析: 有两种可能,第一种为正常从[1 - n]序列中的最大子字段和:第二种为数组的total_sum - ([1-n]序列中的最短序列和) 最后结果为 max { 第一种, 第二种}. 对于第二种: 循环数组求最大子段和,可能出现中间的一部分不要,要两边的数.比如:-1 4 -1 -5 5 -2 1 -1 3,他的最大子段和就为 左边的-1 4加上右边的5 -2 1 -1 3,也就是,去掉1 -5这一段后的结果.而

1050 循环数组最大子段和

个整数组成的循环序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input 第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数 (-10^9 <= S[i] <

HDU 1024 Max Sum Plus Plus --- dp+滚动数组

HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值,其中第i个子序列包括a[j], 则max(dp[m][k]),m<=k<=n 即为所求的结果 <2>初始状态: dp[i][0] = 0, dp[0][j] = 0; <3>状态转移: 决策:a[j]自己成为一个子段,还是接在前面一个子段的后面 方程: a[j]直接接在前面

二维循环数组

一.题目与要求 题目.返回一个二维整数数组中最大子数组的和 要求.1.输入一个二维整形数组,数组里有正数也有负数. 2.二维数组首尾相接,象个一条首尾相接带子一样. 3.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和 二.设计思路 在上一次的以为循环数组的基础上,和二维数组求最大子数组相结合,将功能合并,完成题目要求. 第一步.将每一行的数组作为循环数组求最大子数组 第二步.通过枚举的方式,将每一种情况的和存入到新建二维数组中 第三部.通过逐列计算最大子数组的方法求所有子矩阵的最

求最大子数组(循环数组)

一.设计思想: 通过一个for循环.数组分别从0-最大,1-最大-0 等等依次 到最大-最大-1,通过这样的方式达到循环数组的目的.然后在每一个的数字里面,从第一个数开始向后按顺序相加,当相加结果为负数的时候,则此时不满足构成最大子数组的条件,然后从导致数组为负数的数的下一个数开始向后相加.最后求得此情况下的最大子数组和.然后分别求出N个最大子数组的和,然后在进行比较大小,得出最终的最大子数组的和. 二.出现的问题: 起初并没有实现在一个首尾相接的数组中,最大子数组和为正确值,例如 1 -2 -

循环数组最大子段和(动态规划思想的巧妙转换)

个人心得:这是一道好题,线性的最大字段和在动态规划中是司空见惯的.所以对于这种动态规划的思想的巧妙转变也是需要 锻炼的,就像在暑假集训里面碰到的从1到k是递增,k到n是递减的k使得此时的和最大,当时也是毫无办法,虽然后面 想到了分别将首尾展开然后分别求递增的最大和,题目就迎刃而解了.其实这一题题目的分解还是很明白的, 最大值无非就是线性动态规划和横跨俩端的子段,横跨俩端的子段最简单就是俩层循环很明显超时了,后面想着从左边找到最大 的并标志,但是很明显俩段最大值不一定是在一段最大值的前提下,所以后

区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现

区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断 n堆石子排列成一条线,我们可以将相邻的两堆石子进行合并,合并之后需要消耗的代价为这两堆石子的质量之和,问最小的合并代价 状态转移方程很容易给出: f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) 因为要计算区间和,考虑前缀和进行预处理 然后我们给出用记忆化搜索形式实现的代码,这里的记忆化搜索形式可以作为后续问题的一个模