赞
踩
以数组的 center = (right-left)/2 位置处分开。形成两个子数组。
那么,最大子段和 可能出现在三个位置:
1.可能出现在 left子数组 ——>a[1,(n/2)]
2. 可能出现在 right子数组——>a[(n/2)+1,n)]
3.可能出现在 过center的 中间某部分 元素 组成的子数组
p表最左位置
q表最右位置
——>a[p,q]即1=<p=<n/2 , n/2+1=<q=<n
下面考虑 三种情况的计算方法:
第一种情况: 计算 left 到 center 的最大和,记作 left_sum
第二种情况: 计算从 center+1 到 right的最大和,记作 right_sum
第三种情况: 跨边界的和。 以center为中心分别向两边计算和。
1.从 center出发,每次向左边遍历一次,就累加到lefts,如果当前的和比上次的和大,就赋给s1,一直向左直到位置 left。
2.从 center+1出发,每次向右边遍历一次步,就累加到rights,如果当前的值比上次的和 大,就赋给s2,一直向右直到位置right。
3.计算过center的连续值的和,s1+s2的和值 , 这个就是跨边界的和。
上面三种情况考虑计算完成后,最后一步就是,比较三个值中的最大值,取最大值即可。
- #include<stdio.h>
- #include<stdlib.h>
- #define N 100010
- //#include<bits/stdc++.h>
- //using namespace std;
-
- int max_sum(int a[],int n)
- {
- return max_sub_sum(a,1,n);
- }
- int max_sub_sum(int a[],int left,int right)
- {
- int center,i,left_sum,right_sum,s1,s2,lefts,rights;
- if(left==right)
- {
- if(a[left>0]) return a[left];
- else return (0);
- }else{
- center=(left+right)/2;
- left_sum=max_sub_sum(a,left,center);// 左边最大子段
- right_sum=max_sub_sum(a,center+1,right);// 右边最大子段
- }
- //求中间最大子段
- s1=0;lefts=0;
- for(i=center;i>=left;i--)
- { // 注意:这里是从中间向左遍历,目的是为了让划分的左右两边序列能连接起来
- lefts+=a[i];
- if(lefts>s1) s1=lefts;
- }
- s2=0;rights=0;
- for(i=center+1;i<=right;i++)
- {
- rights+=a[i];
- if(rights>s2) s2=rights;
- }
- if(s1+s2<left_sum && right_sum<left_sum) return (left_sum);
- if(s1+s2<right_sum) return (right_sum);
- return s1+s2;
-
- }
- void display(int a[],int n)
- {
- int i;
- for(i=1;i<=n;i++)
- {
- printf("%d ",a[i]);
- }
- printf("\n");
- }
-
- main(){
- /*-2 11 -4 13 -5 -2*/
- int n,a[N],i,sum=0;
- printf("input:");
- scanf("%d",&n);
- for(i=1;i<=n;i++)
- {
- scanf("%d",&a[i]);
- }
- printf("output:");
- display(a,n);
- printf("最大子段和为:");
- printf("%d",max_sum(a,n));
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。