开始学习动态规划了,前面已经浅学了01背包,所以现在理解起最简单的动态规划也不是太难。先给大家介绍一下这是动态规划的英文名dynamic programming,简称dp。我在前面的博客中发表了我对01背包的看法和我的一些理解 想了解一下的可以点开哦 Max sum这道题呢,也算是最简单的动态规划题了。作为一个初学者,我觉得有必要写一下这篇,加深我对动态规划的理解。也请动态规划的大佬们来帮我指点指点,还有就是也请还不是太理解动态规划的小伙伴们来和我一起理解理解。一起学习嘛不说多的废话了,先把题目弄上来
Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.
InputThe first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).
OutputFor each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.
Sample Input
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5
Sample Output
Case 1:
14 1 4
Case 2:
7 1 6
其实我看到这题并翻译好题目以后呢,我是有点蒙圈的,我的第一想法是直接不选择负数,整数一起相加就结了嘛。后来我才知道,这子序列是必须连续的。题目也没有说清楚。这题很明显是动态规划嘛,前面也说过,属于最简单的dp题。先附上几行代码
int first=1,final=1,x=1,max=a[1],sum=a[1];//first和final呢是题目要求的第一个数和最后一个数。
for(int i=2;i<=n;i++){//sum该不该加上a[i];
if(sum+a[i]<a[i]){//因为加上了还没a[i]大,所以不应该加
x=i;
sum=a[i];
}
else {//和上面情况相反,所以应该加
sum+=a[i];
}
if(sum>max){//如果此时的sum比max还大,那么进行替换
max=sum;
first=x;
final=i;
}
}
上面的代码附有解析。相信还是可以蛮轻松的看懂吧。看懂是可以看懂,那为什么要这么做呢?就比如在判断应不应该加上a[i]的时候为什么是比较sum+a[i]和a[i],而不是比较sum+a[i]和sum呢?这个问题就是我先开始做这道题的时候犯的错误,是蛮蠢的。虽然可能跟我一样这么想过的小伙伴们少之又少,但我还是有必要说一下 ,原因很简单,就是因为这子序列必须是要连续的。如果加了以后比没加还小,说明sum已经是负数了,这时候就有必要把连续的给断开了。还有很重要的一点就是sum并不是max。先把完整的代码给弄上来。
#include<stdio.h>
int a[100001];
int k=0;
int main()
{
int t,n,q;
scanf("%d",&t);
q=t;
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int first=1,final=1,x=1,max=a[1],sum=a[1];//first和final呢是题目要求的第一个数和最后一个数。
for(int i=2;i<=n;i++){//sum该不该加上a[i];
if(sum+a[i]<a[i]){//因为加上了还没a[i]大,所以不应该加
x=i;
sum=a[i];
}
else {//和上面情况相反,所以应该加
sum+=a[i];
}
if(sum>max){//如果此时的sum比max还大,那么进行替换
max=sum;
first=x;
final=i;
}
}
printf("Case %d:\n%d %d %d\n",++k,max,first,final);
if(k!=q) printf("\n");
}
return 0;
}
感觉就这样就可以做出这道题了?是不是没有明确的dp的味道?如果有这种感觉的话,那我有必要抛开这道题的要求限制,试着把状态转移方程写一下。
sum[i]=max(sum[i-1]+a[i],a[i]);再附上几行代码
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100001],sum[1000001];
int nmax;
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
scanf("%d",&a[1]);
nmax=a[1];
sum[1]=a[1];
for(int i=2;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=max(sum[i-1]+a[i],a[i]);//这行就是状态转移啦
nmax=max(sum[i],nmax);
}
printf("%d\n",nmax);
}
}