Max Sum
问题描述
大意:
给定一个序列a[1],a[2],a[3]…a[n],你需要算出其子序列中的最大值。比如说:给你一个序列(6,-1,5,4,-7),它的子序列之和中的最大值是6 + (-1) + 5 + 4 = 14。
输入
大意:
第一行是一个范围在1到20的整数T,代表着接下来输入的测试案例;
接下来的T行,每一行都首先是一个范围在1到100000的数字N,代表着该测试案例中所包含的测试数据个数。其次,接着就是N个范围在-1000到1000的测试数据。
输出
大意:
对于每一个测试案例结果,输出两行。
第一行是 “Case #:”,#代表着测试案例的序号;
第二行是三个数据,分别是最大子序列之和、子序列在原序列中的起始位下标加一和末位下标加一;
如果测试案例不止一个,输出测试案例结果之间需要有一个空行。
算法思想:
这道题用到的算法思想是动态规划,鉴于该题是入门级的动态规划题,我就简单讲一下我对动态规划的基础认识。
比如说,1+1+1+1+1=5,那么再加1呢,等于6。可以发现,我们非常快地得出了答案,那是因为我们记住了上一个结果是5,5+1=6。如果我们重新1+1+1+1+1+1=6,那么肯定会慢,而且会造成许多不必要的浪费。
于是为了解决冗余,我们把从一开始逐步得出的结果记录下来,直到最终得到答案。所以总的来说,这是一个牺牲空间换取时间的算法
解题思路:
在输入数据同时,数据加到序列和里,边加边比较。最大值小于序列和时,最大值更新,记录起始位,末位数更新为现位。若序列和小于0时,序列和置0,起始位更新为下一位。
C++版AC代码
#include<iostream>
using namespace std;
int main(){
int n,m,k,sum,max,x,y,head;
cin>>n;
for(int i=0;i<n;i++){
head=1;
y=0;
x=0;
sum=0;
max = -32768;
cin>>m;
for(int j=1;j<=m;j++){
cin>>k;
sum+=k;
if(max<sum){
max=sum;
y=j;
x=head;
}
if(sum<0){
sum=0;
head=j+1;
}
}
cout<<"Case "<<(i+1)<<":\n"<<max<<" "<<x<<" "<<y<<endl;
if(i<n-1)
cout<<endl;
}
}
C++运行展示:
JAVA版AC代码
import java.util.Scanner;
class count1003{
int head,x,y,sum,max;
public count1003(){}
public void sumOfSub_Sequence(int[] a,int m,int i){
this.head=1;
this.y=0;
this.x=0;
this.sum=0;
this.max = -32768;
for(int j=1;j<=m;j++){
sum+=a[j];
if(max<sum){
max=sum;
y=j;
x=head;
}
if(sum<0){
sum=0;
head=j+1;
}
}
System.out.println("Case "+(i+1)+":");
System.out.println(max+" "+x+" "+y);
}
}
class Main{
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
count1003 count = new count1003();
int n,m;
int[] sequence = new int[100000];
n=scan.nextInt();
for(int i=0;i<n;i++){
m=scan.nextInt();
for(int j=1;j<=m;j++){
sequence[j] = scan.nextInt();
}
count.sumOfSub_Sequence(sequence,m,i);
if(i<n-1) System.out.println();
}
scan.close();
}
}
JAVA运行展示: