【题目链接】:​​click here~~​​ 

【题目描述】:


题目1372:最大子向量和(连续子数组的最大和)

时间限制:1 秒

内存限制:32 兆

特殊判题:否

提交:2987

解决:784



题目描述:

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天JOBDU测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?

输入:


输入有多组数据,每组测试数据包括两行。

第一行为一个整数n(0<=n<=100000),当n=0时,输入结束。接下去的一行包含n个整数(我们保证所有整数属于[-1000,1000])。


输出:


对应每个测试案例,需要输出3个整数单独一行,分别表示连续子向量的最大和、该子向量的第一个元素的下标和最后一个元素的下标。若是存在多个子向量,则输出起始元素下标最小的那个。

样例输入:


3 -1 -3 -2 5 -8 3 2 0 5 8 6 -3 -2 7 -15 1 2 2 0

样例输出:


-1 0 0 10 1 4 8 0 3

【思路】:考虑DP,函数F(i)表示已第i个数字结尾的子数组的最大和,那么我们需要求出max(F[i]),其中0<=i<n。


我们得到如下递归公式:


             

【剑指offer之最大子向量和(连续子数组的最大和)】_数组


公式的意义:当以第i-1个数字结尾的子数组中所有数字的和小于0时,如果把这个负数与第i个数相加,得到的结果比原先还小,所以这种情况以第i个数字结尾的子数组就是第i个数本身。如果以第i-1个数字结尾的子数组中所有数字的和大于0,与第i个数累加就得到以第i个数结尾的子数组中所有数字和。

对于记录开始与结束位置下标,我们知道,每当当前子数组和的小于0时,便是新一轮子数组的开始,每当更新最大和时,便对应可能的结束下标,这个时候,只要顺便用本轮的起始和结束位置更新始末位置就可以,程序结束,最大子数组和以及其始末位置便一起被记录下来了。

【代码】:


#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <stack>
#include <math.h>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const LL MOD = 999999997;
const int inf= 0x3f3f3f3f;
int dir4[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
int dir8[8][2]= {{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
/*Super waigua */

inline int read(){
int c=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
return c*f;
}
int a[maxn];
int max_sum_of_arr(int *a,int n)
{
int cur_begin=0,begin=0,end=0;
int sum=-inf;
int cur_sum=0;
for(int i=0; i<n; ++i)
{
if(cur_sum<0) {cur_sum=a[i];cur_begin=i; }
else cur_sum+=a[i];
if(cur_sum>sum){sum=cur_sum;begin=cur_begin;end=i;}
}
printf("%d %d %d\n",sum,begin,end);
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m;
while(~scanf("%d",&n)&&n)
{
for(int i=0; i<n; ++i) a[i]=read();
max_sum_of_arr(a,n);
}
return 0;
}

/**************************************************************
Problem: 1372
User: herongwei
Language: C++
Result: Accepted
Time:190 ms
Memory:1908 kb
****************************************************************/


【剑指offer之最大子向量和(连续子数组的最大和)】_数组_02