这是一道动态规划的题目,刚学了一点动态规划还不太熟悉,这一道题研究了很久才做出来
题目大意:
输入n个数字,其中的数字可以按排列顺序相加,找出相加值最大的子序列,输出该最大值和起点终点
思路:
该题使用dp来做,整体的思路根据 max{dp[i]+sum, dp[i]} 来判断, 数字相加不是一遇到负数就停止相加,而是直到发现之前相加的结果成了负数为止。
我们可以设置变量ans存储最终的结果、变量temp暂时存储目前相加得到的结果,同时要记录是从第几个数开始相加,到第几个数停止,每相加一次后temp都会改变,如果temp大于ans就更新结果。
这是一个边记录最大值边尝试的过程,每一次temp大于ans时更新最大值。当dp[i]是一个正数时相加后temp肯定会更大所以就毫不犹豫继续往后相加;当dp[i]是一个负数时相加后temp肯定会变小,但只要temp仍然不是一个负数,即是暂时变小了一些但通过之后的相加还是有可能变得更大,所以我们要给dp[i]<0一个机会,j继续往后相加,希望让之后的数来弥补减去的这部分,就算之后不断相加temp还是没有减小之前大也没关系,因为在ans中已经存放了最大的情况。如果temp一直与负数相加最后可能会变成一个负数,此时下一个数就算是一亿,相加后temp会变成一个很大的数,但仍然比一亿小,负数的部分对这个一亿来说却是一个累赘,远不如直接舍弃之前的所有数,从一亿重新开始向后相加。
完整代码如下:
#include<stdio.h>
int main() {
int t, n ;
int data[100005] ;
int temp, ans, first, last, x, y ;
scanf("%d", &t) ;
for(int i=1; i<=t; i++) {
scanf("%d", &n) ;
for(int j=0; j<n; j++)
scanf("%d", &data[j]) ;
x = y = first = last = temp = 0 ;
ans = -1000000 ;
for(int j=0; j<n; j++) {
if(temp+data[j] >= data[j]) { //只有temp为负数时再加多大的数都不如直接从新的数开始
temp += data[j] ;
last = j ;
}
else {
temp = data[j] ; //从新的点开始计
first = last = j ;
}
if(temp > ans) { //更新结果
ans = temp ;
x = first ; //开始
y = last ; //停止
}
}
printf("Case %d:\n", i) ;
printf("%d %d %d\n", ans, x+1, y+1) ; //因为从0开始所以要加一
if(i < t)
printf("\n") ;
}
return 0 ;
}
总结:
dp不好搞。。。。