好久没做题了,望我能跨过这道坎。
DP其实自己原先做了好久还是跟没入门一样……有点不得其法……到底是哪方面能力差……
好啦,说说想法。是看了题解还是不懂的……之前脑子里一直模拟程序是怎么走的,但是真不知道为什么这样,然后刚刚……换了一种方式……我也不知道这样靠谱不……反正……看着像对的?不对的话也是我证明的方面还不够吧。
设dp[i]为以a[i]结尾的最大子序列和。
证明:dp[i]为以a[i]结尾的最大子序列和
解:1.dp[i+1]是为以a[i+1]结尾的最大子序列和
2.dp[0]满足假设
易得2成立
即证1.
因为dp[i]是以a[i]结尾的最大子序列和,若dp[i+1]=max(dp[i]+a[i],a[i]),则2.成立。
得证。
(⊙v⊙)嗯。。。。不知道是不是这样。。。
所以这个dp的转移方程就是这个啦。
#include <stdio.h> #define ll long long #define maxn 10010 ll a[maxn]; typedef struct node { ll val,l,r; }node; node dp[maxn]; int max(int a,int b) { return a>b?a:b; } int main() { int n; while(scanf("%d",&n)!=EOF&&n) { int i,j=0; for(i=0;i<n;i++) { scanf("%lld",&a[i]); if(a[i]>=0) j=1; } if(!j) { printf("0 %lld %lld\n",a[0],a[n-1]); continue; } dp[0].val=a[0]; dp[0].l=dp[0].r=a[0]; for(i=1;i<n;i++) { ll tmp=dp[i-1].val+a[i]; if(tmp>a[i]) { dp[i].val=tmp; dp[i].r=a[i]; dp[i].l=dp[i-1].l; } else { dp[i].val=a[i]; dp[i].l=dp[i].r=a[i]; } //printf("---%d %d %d\n",dp[i].val,dp[i].l,dp[i].r); } node sum; sum=dp[0]; for(i=1;i<n;i++) if(dp[i].val>sum.val) sum=dp[i]; printf("%lld %lld %lld\n",sum.val,sum.l,sum.r); } return 0; }
************************
这里可以进行优化,两个方面,我们可以发现,每次对比只是dp[i]与dp[i-1]对比。所以不用所有的dp值都保留,只要保留pre now即可。
所以这样一来对于输入的数据也无需储存。
代码就不贴了。。。。。
原来看网络上的极简代码也不知道是怎么来的,现在自己推出来感觉真好。有的时候代码看不懂就要动手算,无厘头的代码可能是推出来的。怎么可以从一个推出来的式子上去意淫呢??!