#include <stdio.h>
long long a[1000006];
long long maxsum,thissum ;;
int main()
{
int n, i;
while(~scanf("%lld", &n))
{
for(i = 0;i < n;i ++)
scanf("%lld", &a[i]);
thissum = 0;
maxsum = -0x7fffffff;
for(i = 0;i < n;i ++)
{
thissum += a[i];
if(thissum > maxsum)
maxsum = thissum;
if(thissum < 0)
{
thissum = 0;
}
}
printf("%lld\n",maxsum);
}
return 0;
}
做这一题却是废了我不少劲,此题并不难 ,就是个简单的动态规划,刚开始由于数组开的太大却没有放外面,导致程序运行不了,然后就是输出和输入格式不对,导致wa了几次,一下分析是一位同学写的,感觉写的挺好,就给拿来了,呵呵
分析:
本题首先要想到要用 long long int 来表示最大序列和,另外还要注意一点就是输入的n个数,同样也要用long int 表示,不然也会越界。看到这题有很多方法,相对来说动态规划是比较简洁的。
下面列出推出其状态转移方程的过程。
a[i]是输入的原始数列元素,sum[i]是从a[1]~a[i]之间包含a[i]的最大子段和,将sum[i]都求出来后,最最大值即为所求。(sum[]要用long long int)
假设sum[i-1]已经求出,那么要求sum[i],就要看sum[i-1]加上a[i]和a[i]哪个大 即sum[i]=max(sum[i-1]+a[i],a[i]) 这里有点要理解的地方,因为题目中要求的是连续子序列,所以sum[i]=max(sum[i-1]+a[i],a[i])而不是 sum[i]=max(sum[i-1]+a[i],sum[i-1]),因为如果是后面的式子的话其求的的子序列不是连续的,这就不符合题目要求。
下面就可以写出计算sum[i]的伪码
sum[0]= a[0];
int
maxSum = sum[0];
for
(inti = 1; i < n; i++)
{
sum[i]= max(sum[i - 1] + a[i], a[i]);
maxSum= max(maxSum, sum[i]);
}
最终maxSum 保存的就是sum[i]中的最大值。
下面使用二分法写的一个求最大子序列和,因为过不了,只是写了一个大概的思路,贴给大家看看:
#include <stdio.h>
#define INFE -65535
int max(int a,int b,int c)
{
int m = a;
if(m < b)
m = b;
if(m < c)
m = c;
return m;
}
int a[1000];
int MAX_sum(int l, int r)
{
int i, j;
if(l == r )
{
//if(a[l] > 0)
return a[l];
//else return 0;
}
int mid = (l + r) / 2;
if(l < r)
{
int left_num, right_num, mid_lnum, mid_rnum;
// if()
left_num = MAX_sum(l, mid);
right_num = MAX_sum(mid + 1, r);
int Max_lsum, Max_rnum, Max;
mid_rnum = mid_lnum = 0;
Max_lsum = Max_rnum = INFE;
for(i = mid;i >= l;i --)
{
mid_lnum += a[i];
if(mid_lnum > Max_lsum)
Max_lsum = mid_lnum;
}
for(i = mid + 1;i <= r;i ++)
{
mid_rnum += a[i];
if(mid_rnum > Max_rnum)
Max_rnum = mid_rnum;
}
Max = Max_rnum + Max_lsum;
return max(left_num, right_num, Max);
}
}
int main()
{
int n, i, j, b;
while(~scanf("%d", &n))
{
for(i = 0;i < n;i ++)
scanf("%d", &a[i]);
b = MAX_sum(0, n-1);
printf("%d ",b);
}
return 0;
}