最大子段三种情况
-
最大子段和在左半部分
-
最大子段和在右半部分
-
最大子段和同时跨越左右部分
附题目链接
P1115 最大子段和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
全负数数组要求我们对于第三种情况能够正确更新最大子段和的值
如果代码中ls和rs的值为0,那么第三种情况的值无法更新,因为全负数数组中的值永远小于0,而我们要找的是最接近0的值。
所以我们把ls和rs的初始值设为一个特别小的数,这样就可以正常更新第三种情况的值啦
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int minn = -99999999999999999;
int num[N];
//left左端点下标 right右端点下标
int maxSubSum(int left, int right)
{
int sum = 0;
if (left == right) //递归调用中必要的终止情况
{
sum = num[left];
}
else
{
int center = (left + right) / 2;
int leftMax = maxSubSum(left, center); //求出左序列最大子段和
int rightMax = maxSubSum(center + 1, right);//求出右序列最大子段和
//求跨前后两段的情况,从中间分别向两端拓展
//从中间往左拓展
int ls = minn; //这里是特判全负数数组,起始值设为最小
int lefts = 0;
for (int i = center; i >= left; i--)
{
lefts += num[i];
if (lefts > ls)
ls = lefts;
}
//从中间往右拓展
int rs = minn; //这里是特判全负数数组,起始值设为最小
int rights = 0;
for (int i = center + 1; i <= right; i++)
{
rights += num[i];
if (rights > rs)
rs = rights;
}
sum = rs + ls;//第三种情况的最大子段和
//将三种情况的最大子段和进行比较,得到最大的
sum = max(leftMax, sum);
sum = max(rightMax, sum);
}
return sum;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> num[i];
cout << maxSubSum(0, n - 1) << endl;
}