[拓展]杭电1003(最大子数组问题)
来源:互联网 发布:中国gdp增速放缓知乎 编辑:程序博客网 时间:2024/06/16 06:06
http://acm.hdu.edu.cn/showproblem.php?pid=1003
就题目本身,不考虑时间限制,解法是很多的
首先
可以暴力求解,用三重循环解决
优化一次
省略一次循环,这里给出一段代码(在杭电上超时,还是需要进一步优化)
#include <stdio.h> int MaxSum(int* A,int n,int* i,int* j) { int maximum=-100000,sum,t,p; for (*i=0;*i<n;(*i)++) { sum=0; for (*j=*i;*j<n;(*j)++) { sum+=A[*j]; if (sum>maximum) { maximum=sum; t=*i;p=*j; } } } *i=t+1; *j=p+1; return maximum; } int main() { int n,i,j,m,a[100001],x,y; scanf("%d",&n); for (i=0;i<n;i++) { scanf ("%d",&m); for (j=0;j<m;j++) scanf ("%d",&a[j]); printf ("Case %d:\n%d %d %d\n\n",i+1,MaxSum(a,m,&x,&y),x,y); } return 0; }
第二次优化
可以继续省略一次循环,使用分治策略 分解整个数组为两个子数组,A[low,mid],A[mid+1,high]
分三种情况
1. maximum位于A[low,mid]中
2. maximum位于A[mid+1,high]中
3. 跨越中点 low<=i<=mid<=j<=high 在此即可省略一次for,记录各段中相加的最大值,并不断更新
int leftsum=ptrA[mid];//左部最大值 int maxleft=mid;//左边界 int sum=0; for (int i=mid;i>=low;i--) { sum+=ptrA[i]; if (sum>=leftsum) { leftsum=sum; maxleft=i; } } //这里只给出左部的代码,还需写出贯穿时和右部的代码,不一一列举 //其中,贯穿时,其范围是由上述第三点确定的
变换思路,动态规划
至于为什么有人把优化一当成动态规划,我就不得而知了。。。
int max(int x,int y) { return (x>y?x:y);} int maxsum(int *A,int n) { start[n-1]=A[n-1]; ALL[n-1]=A[n-1]; for (i=n-2;i>=0;i--) { start[i]=max(A[i],A[i]+start[i+1]); ALL[i]=max(start[i],ALL[i+1]); } return ALL[0]; }//这里给出完整的代码 #include<iostream> #define inf 0x3f3f3f using namespace std;int a[100001],s[100001],t[100001]; int main() { int m,n,i,j,p,q,max; cin>>n; for(i=1;i<=n;i++) { if(i!=1) cout<<endl; cin>>m; for(j=1;j<=m;j++) cin>>a[j]; t[0]=-1; s[0]=0; for(j=1;j<=m;j++) { if(t[j-1]>=0) { t[j]=t[j-1]+a[j]; s[j]=s[j-1]; } else { t[j]=a[j]; s[j]=j; } } max=-inf; p=0; q=0; for(j=1;j<=m;j++) if(t[j]>max) { max=t[j]; p=s[j]; q=j; } cout<<"Case "<<i<<":"<<endl; cout<<max<<" "<<p<<" "<<q<<endl; } return 0; }
由于是第一次接触动态规划,所以最开始也看不懂,后来看了别人的分析,就清楚很多了,这里给出引用的链接http://alorry.blog.163.com/blog/static/6472570820123801223397/
对于整个序列a[n]来说,它的所有子序列有很多很多,但是可以将它们归类。
注意,是以结尾的子序列,其中肯定是要包含的了
以a[0]结尾的子序列只有a[0]
以a[1]结尾的子序列有 a[0]a[1]和a[1]
以a[2]结尾的子序列有 a[0]a[1]a[2] / a[1]a[2] / a[2]
……
以a[i]结尾的子序列有a[0]a[1]……a[i-2]a[i-1]a[i] / a[1]a[2]……a[i-2]a[i-1]a[i] / a[2]a[3]……a[i-2]a[i-1]a[i] / …… / a[i-1]a[i] / a[i]
所有以a[0] ~a[n]结尾的子序列分组构成了整个序列的所有子序列。
这样,我们只需求以a[0]~a[n]结尾的这些分组的子序列中的每一分组的最大子序列和。然后从n个分组最大子序列和中选出整个序列的最大子序列和。
观察可以发现,0,1,2,……,n结尾的分组中,
maxsum a[0] = a[0]
maxsum a[1] = max( a[0] + a[1] ,a[1]) = max( maxsum a[0] + a[1] ,a[1])
maxsum a[2] = max( max ( a[0] + a[1] + a[2],a[1] + a[2] ),a[2])
= max( max( a[0] + a[1] ,a[1]) + a[2] , a[2])
= max( maxsum a[1] + a[2] , a[2])
……
依此类推,可以得出通用的式子。
maxsum a[i] = max( maxsum a[i-1] + a[i],a[i])
- [拓展]杭电1003(最大子数组问题)
- 杭电ACM1003 最大子数组之和
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 最大子数组问题
- 【Windows编程】系列第九篇:剪贴板使用
- 摄像机标定方法(二)----Faugeras的摄像机标定方法
- zoj_1002
- 黑马程序员———Java编程基础之数组
- JackSon 数据之间的转换 java
- [拓展]杭电1003(最大子数组问题)
- cin与cout
- 1、为什么每个viewDidLoad方法中都要使用[super viewDidLoad] ?
- 字符串替换 hihoCoder1082 然而沼跃鱼早就看穿了一切
- 在Linux系统下安装mysql
- 学习hadoop(2)单词统计
- 【C++ STL学习之五】容器set和multiset
- ssh常用用法小结
- 黑马学习笔记_javaIO(二)