欢迎访问我的个人网站==》 jiashubing.cn

最大连续子段和

最大连续子段和

•          给定长度为n的整数序列,a[1...n], 求[1,n]某个子区间[i,j]使得a[i]+…+a[j]和最大,或者求出最大的这个和。例如(-2,11,-4,13,-5,2)的最大子段和为20,所求子区间为[2,4]。

 

•       穷举法(3次for循环)

           第1次for循环,遍历数组所有数字,即确定子段和的首个数字;

          第2次for循环,遍历数个数字之后的所有数字,即确定字段和的最后一个数字;

          第3次for循环,遍历首个数字与最后一个数字,对之间所有数字求和。

 1 int maxSum(int a[], int num, int &start, int &end){
 2     int localSum= MINNUM;
 3     for (int i = 0; i < num; i++){
 4         for (int j = i; j < num; j++){
 5             int thisSum = 0;
 6             for (int k = i; k <= j; k++){
 7                 thisSum += a[k];
 8             }
 9             if (thisSum > localSum){
10                 start = i;
11                 end = j;
12                 localSum = thisSum;
13             }
14         }
15     }
16     return localSum;        
17 }

•       穷举优化法(2次for循环)

           第1次for循环,遍历数组所有数字,即确定子段和的首个数字;

          第2次for循环,遍历数个数字之后的所有数字,即确定字段和的最后一个数字;

          用thisSum记录不同结尾数字对应的子段和,进而比较获得对应首个数字的最大子段和

 1 int maxSum(int a[], int num, int* start, int* end){
 2     int localSum= 0;
 3     for (int i = 0; i < num; i++){
 4         int thisSum = 0;
 5         for (int k = i; k < num; k++){
 6             thisSum += a[k];
 7             if (thisSum > localSum){
 8                 *start = i;
 9                 *end = k;
10                 localSum = thisSum;
11             }
12         }
13     }
14     return localSum;        
15 }

•       分治策略

           将初始最大子段和问题分解为两个相同的子问题;

    •     分别对相同的子段求解最大子段和;

    •     合并子问题的解,获得原问题的解。

             最大子段和位于左子段

             最大子段和位于右子段

             最大子段和的首数字位于左子段,尾数字位于右子段

 1 int maxSum(int a[], int left, int right){
 2     int localSum = 0;
 3     if (left == right) localSum = (a[left] > 0 ? a[left] : 0); 
 4     else{
 5         int mid = (left + right)/2;
 6         int leftSum = maxSum(a, left, mid);
 7         int rightSum = maxSum(a, mid + 1, right);
 8         int sum1 = 0;     int lefts = 0;
 9         for (int i = mid; i >= left; i--){
10             lefts += a[i];
11             if (lefts > sum1)   sum1 = lefts;    
12         }
13         int sum2 = 0;  int rights = 0;
14         for (int i = mid + 1; i <= right; i++){
15             rights += a[i];
16             if (rights > sum2)  sum2 = rights;
17         }
18         localSum = sum1 + sum2;
19         if (localSum < leftSum) localSum = leftSum;
20         if (localSum < rightSum) localSum = rightSum;
21     }            return localSum;                 
22 }

       动态规划

         令b[j]表示以位置 j 为终点的所有子区间中和最大的一个

    子问题:如j为终点的最大子区间包含了位置j-1,则以j-1为终点的最大子区间必然包括在其中

        如果b[j-1] >0, 那么显然b[j] = b[j-1] + a[j],用之前最大的一个加上a[j]即可,因为a[j]必须包含

        如果b[j-1]<=0,那么b[j] = a[j] ,因为既然最大,前面的负数必然不能使你更大

 1 int maxSum(int a[], int num)
 2 {
 3     int localSum = 0;
 4     int b = 0;
 5     for (int i = 0; i < num; i++)
 6     {
 7         if (b > 0)
 8             b += a[i];
 9         else 
10             b = a[i];
11         if (b > localSum)
12              localSum = b;
13     }
14     return localSum;        
15 }

   算法效率分析

         穷举法       O(n3)

        穷举优化法   O(n2)

        分治法       O(nlogn)

        动态规划法   O(n)

  附带一些完整代码:

 1 //动态规划
 2 # include<stdio.h>
 3 # include<stdio.h>
 4 int maxsum(int a[],int num)
 5 {
 6     int localsum=a[0];
 7     int b=0;
 8     for(int i=0;i<num;i++)
 9     {
10         if(b>0)
11             b += a[i];
12         else
13             b=a[i];
14         if(b>localsum)
15             localsum=b;
16     }
17     return localsum;
18 }
19 int main()
20 {
21     int a[15];
22     int n,i;
23     while(scanf("%d",&n)!=EOF){
24         for(i=0;i<n;i++)
25             scanf("%d",&a[i]);        
26         printf("%d\n",maxsum(a,n));
27     }
28     return 0;
29 }
30 //分治算法
31 # include<stdio.h>
32 int maxsum(int a[],int left,int right)
33 {
34     int localsum=0,i;
35     if(left==right) 
36         localsum=(a[left]>0)?a[left]:0;
37     else{
38         int mid=(left+right)/2;
39         int leftsum=maxsum(a,left,mid);
40         int rightsum=maxsum(a,mid+1,right);
41         int sum1=0; int lefts=0;
42         for(i=mid;i>=left;i--){
43             lefts+=a[i];
44             if(lefts>sum1) sum1=lefts;
45         }
46         int sum2=0; int rights=0;
47         for(i=mid+1;i<=right;i++){
48             rights+=a[i];
49             if(rights>sum2) sum2=rights;
50         }
51         localsum=sum1+sum2;
52         if(localsum<leftsum) localsum=leftsum;
53         if(localsum<rightsum) localsum=rightsum;
54     }
55     return localsum;
56 }
57 int main()
58 {
59     int a[15];
60     int n,temp,i,j,k,max;
61     while(scanf("%d",&n)!=EOF){
62         for(i=0;i<n;i++)
63             scanf("%d",&a[i]);
64         printf("%d\n",maxsum(a,0,n-1));
65     }
66     return 0;
67 }
68 
69 //暴力解法
70 # include<stdio.h>
71 int main()
72 {
73     int a[15];
74     int n,temp,i,j,k,max;
75     while(scanf("%d",&n)!=EOF){
76         for(i=0;i<n;i++)
77             scanf("%d",&a[i]);                
78         max=0;
79         for(i=0;i<n;i++)
80         {
81             for(j=i;j<n;j++)
82             {
83                 int temp=0;
84                 for(k=i;k<=j;k++)
85                     temp+=a[k];
86                 if(temp>max)
87                     max=temp;
88             }
89             
90         }
91         printf("%d\n",max);
92     }
93     return 0;
94 }
View Code

 

posted @ 2013-06-22 13:27  贾树丙  阅读(1065)  评论(0编辑  收藏  举报