Maximum Subsequence Sum 最大子列和算法拓展 浙大考研复试题
Maximum Subsequence Sum 最大子列和算法拓展 浙大考研复试题
标签(空格分隔): 算法 数据结构 算法竞赛
题目描述也很像最大子列和问题。给出一个整型数组,求他的最大子序列和,并且输出和最大时子序列的首元素和末元素。特别的,如果存在最大和相等的情况,就输出下标最小的那组;如果该数组全是负数,就输出0,以及首元素和末元素的值,相互之间用空格隔开。
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
看着很简单的一道题,但是我做了好几遍,老是错。思路很重要,思路搞明白了,就只是三四行代码的问题了。求最大子序列和的最快算法我就不介绍了,之前的文章里面有写,很简单。但是要注意,那个普适性的算法只能求到最大和的结果,并不能确定最大和子序列的首元素和末元素。我们的目的,是确定最大序列中的首末下标,那么,怎样达成这个目的呢?
这里,就考察对这个算法的理解问题了。由求和算法可知,每次更换序列首,发生在sum<0时;但是要注意,在sum<0,i后移时,它还不一定会更换为序列首,只有当sum>max时才会更换。所以,我们可以先设定一个变量,保存可能更换的序列首,再判断他是否大于已保存的最大值,如果大于,才替换首元素下标。之后,我们需要确定序列尾,这个考虑起来很简单。考虑到每次sum>max时,才会更换序列尾,那就可以将赋值语句放在这个条件分支下。
#include <iostream>
#include <algorithm>
#define N 10005
using namespace std;
int main() {
int i,n,a[N],low=0,high=0,max=-1,sum=0,t=0,flag=0;
scanf("%d",&n);
for (i=0;i<n;i++) {scanf("%d",&a[i]);}
for (i=0;i<n;i++) {
sum+=a[i];
if (sum>max) { //说明序列中存在正数
high=i; //high表示最大和序列末元素下标
max=sum;
low=t; //low表示最大和序列首元素下标
flag=1;
}
if (sum<0) {
sum=0;
t=i+1; //t为可能的末下标,暂时保存
}
}
if (flag==0) //说明序列中没有正数
printf("%d %d %d\n",0,a[0],a[n-1]);
else
printf("%d %d %d\n",max,a[low],a[high]);
return 0;
}
代码的关键部分我早就写出来了,但没想到这道题后面部分还是卡了我很久,就是对这个数列中元素全部小于0的情况的处理。其实这时候不用考虑很多的,因为题干里面也给了限制,这时候就直接max=0就行了。但是我又考虑到0的情况,所以就写了好几个分支条件,最后发现都没用。由于这里是一个整型数列,所以负数列最大子序列和最大才会是-1,所以我就设了-1.只有和大于-1时,才会被指定输出。如果没有大于-1的情况,flag就不会为真,就输出特殊情况。为什么不把初始max设为0呢?因为,如果设为0,那么就不能处理既有0又有负数的非正数列了。如果强行处理,就会输出flag=0时的情况,就错了。