题目描述
给出一个长度为n的序列a,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度n。
第二行有n个整数,第i个整数表示序列的第i个数字a[i]。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1
7
2 -4 3 -1 2 -4 3
输出 #1
4
说明/提示
样例1解释:
选取 [3,5][3,5] 子段 {3,−1,2}{3,−1,2},其和为 44。
数据规模与约定:
- 对于 40% 的数据,保证 n≤2×10的三次方n≤2×103。
- 对于 100% 的数据,保证 1≤n≤2×10的五次方,−10的四次方≤ai≤10的四次方。
分析:
解法1:
这道题需要我们在n个数中选取不大于n个数,使它们的和值最大,这就表明我们要在不知道总选择个数的前提下求出最大值。
我们先写基础的输入:
#include<iostream>
using namespace std;
int main()
{
int n,i,a[200000];//注意a数组的大小
cin>>n;
for(i=1;i<=n;i++) cin>>a[i];
}
这里我的思路是将从第一位加到第m位(m是不大于n且大于零的数)存到f[m]中,例如:
位数(m) | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
输入(a数组) | 2 | -4 | 3 | -1 | 2 |
当前总和(f数组) | 2 | -2 | 1 | 0 | 2 |
这里我只取了数据的前五位,如果我们想用第2位到第4位的总和,只需要拿f[4]减f[2],就能得到,这里写出代码:
f[1]=a[1];
for(i=2;i<=n;i++)
{
f[i]=f[i-1]+a[i];//每个f[i]都等于f[i-1]+a[i](除了f[1])
}
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
sum=f[j]-f[i-1];
maxi=max(maxi,sum);//比较大小
sum=0;
}
}
最后输出maxi就能得到值。
AC代码1:
#include<iostream>
using namespace std;
int main()
{
int n,i,a[200000],f[200000],j,k,s1=1,maxi=-100000,sum=0;
cin>>n;
for(i=1;i<=n;i++) cin>>a[i];
f[1]=a[1];
for(i=1;i<=n;i++)
{
f[i]=f[i-1]+a[i];
}
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
sum=f[j]-f[i-1];
maxi=max(maxi,sum);
sum=0;
}
}
cout<<maxi;
return 0;
}
解法2:
这种解法需要运用动态规划,思路是在每次输入时就直接计算和值比较大小并替换,整体更加简洁,并且不使用数组。
AC代码2:
#include<iostream>
using namespace std;
int main()
{
int n,i,a,f=0,maxi=-100000;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a;
if(f+a>a) f=f+a;
else f=a;
maxi=max(maxi,f);
}
cout<<maxi;
return 0;
}