最近想把动规从头练起
设dp[i]为以i结尾的最大连续子序列的和,那么我们可以推测出,dp[i]将依赖于dp[i-1]和n[i],当我们选择n[i]与dp[i-1]中描述的子序列连续时,dp[i]=dp[i-1]+n[i],当我们选择n[i]与dp[i-1]描述的子序列分离时,dp[i]=n[i]。
取这两个结果的最优值,那么dp[i]=max(dp[i-1]+n[i],n[i])。
那么最大和我们就可以最后比较一次dp数组找到,而要完成题目,还需要输出子序列的第一项和最后一项,因为dp[i]记录的是以i结尾的最大连续子序列的和,那么我们可以建立一个对应的from数组,from[i]中记录以第i项结尾的子序列的第一项的位置。那么在更新dp[i]的时候同时更新from[i]。
最后对于这个题有个陷阱,数列全为负数时,答案为“0 第一项 第二项”,而当数列中全为负数和0时,答案应该为“0 0 0”,注意使你的程序能够解决这一点。
(最后说一句,其实这道题可以用sum数组记录前i项的总和然后暴力解决,可能是因为数据太水了吧)
#include <iostream> #include <stdio.h> using namespace std; int num[10010],dp[10010],n,from[10010],anssum=-1,anspos; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>num[i]; dp[1]=num[1]; from[1]=1; for(int i=2;i<=n;i++) { if(dp[i-1]+num[i]>=num[i]) { dp[i]=dp[i-1]+num[i]; from[i]=from[i-1]; //当dp[i-1]+num[i]>=num[i]时,以第i项结尾的子序列的第1项应该是以第i-1项结尾的子序列的第1项 } else { dp[i]=num[i]; from[i]=i; //当num[i]>dp[i-1]+num[i]时,第i项结尾的最大子序列的第1项就是本身. } } for(int i=1;i<=n;i++) { if(anssum<dp[i]) { anssum=dp[i]; anspos=i; } } if(anssum==-1) cout<<"0 "<<num[1]<<" "<<num[n]<<endl; else cout<<anssum<<" "<<num[from[anspos]]<<" "<<num[anspos]<<endl; return 0; }