P1115 最大子段和分治
作者:互联网
P1115 最大子段和
给出一个长度为 nn 的序列 aa,选出其中连续且非空的一段使得这段和最大。
7
2 -4 3 -1 2 -4 3
分治的解法。
首先,假定有区间[l..r][l..r],其中间位置为midmid,其最大子段为[i..j][i..j]。那么显然,ii和jj必定符合下列三种情况之一:
1.l \leq{i} \leq{j} \leq{mid} l≤i≤j≤mid
2.i \leq{mid} <j \leq{r} i≤mid<j≤r
3.mid < i \leq{j} \leq{r} mid<i≤j≤r
只需要分别求出三种情况下的值,取其最大的即可。
其中,很容易求出第二种情况,即求出区间[i..mid][i..mid]与区间[mid+1..j][mid+1..j],将其相加即可。复杂度O(n)O(n)
如何处理第一种和第三种情况呢?也不难发现,第一种情况,其实就是求区间[1..mid][1..mid]中的最大值,第三种情况就是求区间[mid+1..r][mid+1..r]中的最大值。那么,只需递归求出即可。
显然,该解法的复杂度为 O(nlogn)O(nlogn) 通过此题是没问题的。
附上代码
`#include<cstdio>
int n , arr[200200]; //arr存储该序列
const int minn = -19260817; // 定义最小值
inline int Max( int a , int b) { return a > b ? a : b ;} //自定义 Max 函数(好像比stl的快一点)
int rec( int l , int r ) { //分治函数
if ( l == r ) { // l=r时,直接返回该位置的值
return arr[l];
}
int mid = ( l + r ) >> 1;
int sum = 0 , ret1 = minn , ret2 = minn; //ret1为[l..mid]区间内包含mid的最大子段和,ret2为[mid+1..r]区间内包含(mid+1)的最大子段和
for( int i = mid ; i >= l ; i-- ) {
sum += arr[i];
ret1 = Max( ret1 , sum );
} //求出[i..mid]区间最大值
sum = 0;
for( int i = mid+1 ; i <= r ; i++ ) {
sum += arr[i];
ret2 = Max( ret2 , sum );
} //求出[mid+1..r]区间最大值
return Max( Max( rec( l , mid ) , rec( mid + 1 , r ) ) , ret1 + ret2 ); //返回可能一 可能二 可能三 中的最大值
}
int main() { // 以下主函数
scanf("%d", &n );
for( int i = 1 ; i <= n ; i++ ) {
scanf("%d" , &arr[i] );
}
printf("%d" , rec(1 , n) );
return 0;
}`
标签:arr,P1115,..,子段,int,Max,sum,分治,mid 来源: https://blog.csdn.net/m0_46288841/article/details/111683142