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])