动态规划-最大子序列和
今天闲着没事,看了网上一篇文章关于最大子序列的问题,看了算法,自己实现了一下。
所谓最大子序列和是指一个数组所有连续子序列中,和最大的那一组。比如 -1,2,-4,5 的最大子序列是5. 2,-1,3,2,-5的最大子序列为 2,-1,3,2.
动态规划,目前我理解的就是如果想解决一个大问题,先把该大问题分成几个小问题,然后再继续分解直到能解决为止,但是某些小问题的结果可能会被多次用到,所以我们可以把每个结果都保存起来,这样就不用每次用到都去重新计算。
对于本题,我们假设 f(i)为以第i个元素结尾的最大子序列的和。比如 2,-3,5,2 f(0)=2,f(1)=-1,f(2)=5,f(3)=7。注意必须是以i结尾的这样f(1)=-1而不是2。
下面分析f(i+1)的值,f(i+1)是以a[i+1]结尾的,所以f(i+1)=f(i)+a[i+1],或者f(i+1)=a[i+1]。因为f(i)有可能是负的,所以f(i+1)有可能是a[i+1]。
所以我们可以把每个f(i)的值都计算出来,因为,最大和子序列肯定是以某个值结尾的,然后取最大值就可以了。
下面写一下代码
View Code
#include <stdio.h> #include<stdlib.h> int *num; int Method(int i); int Sum=0; int main(void) { int n=0; scanf("%d",&n); num=(int *)malloc(n*sizeof(int)); for(int i=0;i<n;i++) { scanf("%d",&num[i]); } Method(n-1); printf("%d",Sum); } int Method(int i) { if(i==0) { Sum=num[0]; return num[0]; } else { int temp=Method(i-1); int ret; if(temp>0) { ret=temp+num[i]; } else { ret=num[i]; } if(ret>Sum) Sum=ret; return ret; } }
由于每个f(i)只会记录一次,所以不用记录每个值,但是如果会多次用到则需要记录下来,比如菲比那切数列,f(i)=f(i-1)+f(i-1)=f(i-2)+f(i-3)+f(i-1),可以看出每个值会多次用到,所以我们可以开辟一个大小为n的数组存储每个值。此例不用。
下面代码是可以记录最长子序列下标的。
View Code
#include <stdio.h> #include<stdlib.h> int *num; int Method(int i,int &l,int &r); int Sum; int left; int right; int main(void) { int n=0; scanf("%d",&n); num=(int *)malloc(n*sizeof(int)); for(int i=0;i<n;i++) { scanf("%d",&num[i]); } int l,r; Method(n-1,l,r); printf("最长子序列%d 起始坐标%d 终止坐标%d \n",Sum,left,right); printf("\n"); return 0; } int Method(int i,int &l,int& r) { if(i==0) { Sum=num[0]; l=0; r=0; left=0; right=0; return num[0]; } else { int temp=Method(i-1,l,r); int ret; if(temp>0) { ret= temp+num[i]; l=l; r=i; } else { ret=num[i]; l=i; r=i; } if(ret>Sum) { Sum=ret; left=l; right=r; } return ret; } }
其中left right记录的是最大的那个序列的左下标和右下标。l 和r两个引用是为了能获得f(i-1)的序列的左下标和右下标,由于只能有一个返回值,被Sum用了,所以用引用来把下标传回来
注:转载请注明出处 http://www.cnblogs.com/ITPuppy/archive/2013/04/16/3024058.html

浙公网安备 33010602011771号