问题如下:
使用在线处理的方法,“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
算法每次向右累加一次,就进行处理,如果当前的子列和小于0,则再继续向右加也不会是最大值,所以将其抛弃,从下一个数当做果起点从新开始累加。如果当前子列和大于过去的最大子列和,更新之。
代码如下:
#include <stdio.h>
#include <malloc.h>
int main() {
int K = 0;
scanf("%d",&K); //输入K
int * arr = (int *)malloc(sizeof(int)*(K+1));
int i;
for(i=0; i<K; ++i) {
scanf("%d",arr+i); //输入数组
}
printf("%d",MaxSubseqSum(K,arr));
return 0;
}
int MaxSubseqSum(int K, int * arr) {
int MaxSum = 0; //最大子列和
int ThisSum = 0; //当前子列和
int i;
for(i=0; i<K; ++i) {
ThisSum += arr[i]; //向右累加
if(ThisSum < 0) { //如果当前子列和小于0,抛弃
ThisSum = 0;
}
if(ThisSum > MaxSum) { //更新最大值
MaxSum = ThisSum;
}
}
return MaxSum;
}
如果将问题增加为还要输出该子列的第一个和最后一个元素:
要返回该子列的开始和结束元素,首要要定位开始和结束的位置。返回结束位置还是比较容易的,我们知道,每当更新最大和时,便对应可能的结束下标,这个时候,只要将结束位置记录下来即可。当确定最大值后再往回累加便可找到开始位置。
#include <stdio.h>
#include <malloc.h>
int MaxSubseqSum(int K, int * arr, int *FirstNum, int *LastNum);
int main() {
int K = 0;
scanf("%d",&K); //输入K
int * arr = (int *)malloc(sizeof(int)*(K+1));
int i;
for(i=0; i<K; ++i) {
scanf("%d",arr+i); //输入数组
}
int MaxSum,FirstNum,LastNum;
MaxSum = MaxSubseqSum(K,arr,&FirstNum,&LastNum);
if(MaxSum <= 0){ //全是负数
printf("%d %d %d",0,arr[0],arr[K-1]);
}else {
printf("%d %d %d",MaxSum,arr[FirstNum],arr[LastNum]);
}
free(arr);
return 0;
}
int MaxSubseqSum(int K, int * arr,int *FirstNum, int *LastNum) {
int MaxSum = 0; //最大子列和
int ThisSum = 0; //当前子列和
int i;
for(i=0; i<K; ++i) {
ThisSum += arr[i];
if(ThisSum < 0) {
ThisSum = 0;
}
if(ThisSum > MaxSum) {
MaxSum = ThisSum;
*LastNum = i;
}
}
int tempSum = 0;
for(i=*LastNum; i>=0; --i){ //向左累加找到开始下标
tempSum += arr[i];
if(tempSum == MaxSum) {
*FirstNum = i;
break;
}
}
return MaxSum;
}
但测试结果还是不能全部通过