其他分享
首页 > 其他分享> > P1115 最大子段和分治

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