分析:
(1)笨方法,我们可以用普通最大子段和的方法解决这个问题。
我们从每个位置“断开”环,然后按普通的最大子段和的方法去做
。这样做的复杂度是O(n^2)。
(2)巧妙点的方法,我们之所以要从某个位置切开是因为循环的
最大子段和可能是跨越一部分头和尾。
如上图,最优解可能是0..i, j + 1.. n – 1两段,那这时,其实中间
i + 1..j是个“最小子段和”,因为总和是一定得嘛。
所以“循环数组得最大子段和”问题,可以把环从任意位置断开,
然后求出最优解 = max(普通的最大子段和, 总和 – 普通的
“最小子段和”)
求最小子段和,显然也可以用最大子段和的方法求一次就可以了。
(1)笨方法,我们可以用普通最大子段和的方法解决这个问题。
我们从每个位置“断开”环,然后按普通的最大子段和的方法去做
。这样做的复杂度是O(n^2)。
(2)巧妙点的方法,我们之所以要从某个位置切开是因为循环的
最大子段和可能是跨越一部分头和尾。
如上图,最优解可能是0..i, j + 1.. n – 1两段,那这时,其实中间
i + 1..j是个“最小子段和”,因为总和是一定得嘛。
所以“循环数组得最大子段和”问题,可以把环从任意位置断开,
然后求出最优解 = max(普通的最大子段和, 总和 – 普通的
“最小子段和”)
求最小子段和,显然也可以用最大子段和的方法求一次就可以了。
所以循环数组的最大子段和,实际上是求了两次最大子段和而已。
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
long num[50005];
int i,n;
long long as,ad,Max,sum;
while (~scanf ("%d",&n))
{
for (i=0; i<n; i++)
scanf ("%lld",&num[i]);
Max=sum=as=0;
for (i=0; i<n; i++)//最大子段和
{
as+=num[i];//总和
sum+=num[i];
if (sum>Max)Max=sum;
if (sum<0)sum=0;
}
sum=0;ad=10000000000;
for (i=0; i<n; i++)//最小子段和
{
sum=sum+num[i];
if (sum<ad)ad=sum;
if (sum>0)sum=0;
}
ad=as-ad;
if (ad>Max)
printf("%lld\n",ad);
else
printf("%lld\n",Max);
}
return 0;
}