[DP]最大连续子序列-hdu 1231
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1231
算法参考:http://blog.163.com/wuguojin03@126/blog/static/17154113120109510946717/
状态:dp[i]:以i为结尾的最大连续序列和
初始状态:dp[i]=a[i]
状态转移:dp[i]=max{dp[i-1]+a[i],a[i]}
要求最大的,只需从dp[i]找出最大值就行了
以本题输入样例 “ -2 11 -4 13 -5 -2 ” 为例:
序号: 0 1 2 3 4 5
a[]: -2 11 -4 13 -5 -2
dp[]: -2 11 7 20 15 13
观察dp[],终点即为 max:20,起点则为从max往前找最后一个不为负的数,即11
AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream> #include <cstdio> #include <string.h> #include <algorithm> using namespace std; const int N=10010; int a[N],dp[N]; int main() { int n; while (cin>>n && n){ int s=0,e=0; for ( int i = 0; i < n; ++i){ cin>>a[i]; dp[i]=a[i]; } for ( int i=1;i<n;++i){ dp[i]=max( dp[i-1]+a[i] , a[i] ); } //查找最大和及终点 int mymax=-1; for ( int i = 0; i < n; ++i){ if (mymax<dp[i]){ mymax=dp[i]; e=i; } } //查找起点 for ( int i=e;i>=0;--i) if (dp[i]<0){ s=i+1; break ; } if (mymax<0)cout<< "0 " <<dp[0]<< " " <<dp[n-1]<<endl; else cout<<mymax<< " " <<a[s]<< " " <<a[e]<<endl; } return 0; } |
一年后,偶遇此题又做一遍,用的是双dp,效率还没有上面的高:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <algorithm> #include <cstdio> using namespace std; const int MAXN=10000+5; int a[MAXN],dp_l[MAXN],dp_r[MAXN]; int n; int main() { while ( scanf ( "%d" ,&n)&&n>0) { for ( int i=0;i<n;++i){ scanf ( "%d" ,&a[i]); } dp_l[0]=a[0]; dp_r[n-1]=a[n-1]; int ans=a[0],start=0,end=n-1; for ( int i=1;i<n;++i){ dp_l[i]=max(a[i],a[i]+dp_l[i-1]); if (dp_l[i]>ans){ ans=dp_l[i]; end=i; } } ans=a[0]; for ( int i=n-2;i>=0;--i){ dp_r[i]=max(a[i],a[i]+dp_r[i+1]); if (dp_r[i]>=ans){ ans=dp_r[i]; start=i; } } if (ans<0){ ans=0;start=0;end=n-1; } printf ( "%d %d %d\n" ,ans,a[start],a[end] ); } return 0; } |
还有一种方法,也挺快,不过不是用的动态规划:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <algorithm> #include <cstdio> using namespace std; const int MAXN=10000+5; int a[MAXN],dp_l[MAXN],dp_r[MAXN]; int n; int main() { while ( scanf ( "%d" ,&n)&&n>0) { for ( int i=0;i<n;++i){ scanf ( "%d" ,&a[i]); } int start=0,end=n-1,left,ans=a[0],sum=0; for ( int i=0;i<n;++i){ if (sum<0) { //如果前几项和小于0,就重新开始记录 sum=0; left=i; //刷新临时起点 } sum+=a[i]; if (sum>ans){ //如果现在的sum大于原来的max,刷新数据 ans=sum; start=left; end=i; } } if (ans<0){ ans=0;start=0;end=n-1; } printf ( "%d %d %d\n" ,ans,a[start],a[end] ); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步