最大子段和算法分析

最大子段和问题(Maximum Interval Sum)


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

二.算法分析

  1.穷举法

 1 int start = 0;//起始位置
 2 int end = 0;  //结束位置
 3 int max = 0;
 4 for(int i = 1; i <= n; ++i)
 5 {
 6     for(int j = i; j <= n;++j)
 7     {
 8         int sum = 0;
 9         for(int k = i; k <=j; ++k)
10             sum += a[k];
11         if(sum > max)
12         {
13            start = i;
14            end = j;
15            max = sum;
16         }
17     }
18 }

  换一种穷举思路,对于起点 i,我们遍历所有长度为1,2,…,n-i+1的子区间和,以求得和最大的一个.这样也遍历了所有的起点的不同长度的子区间,同时,对于相同起点的不同长度的子区间,可以利用前面的计算结果来计算后面的。就像传递数组参数时往往传的不是起止位置,而是起始位置和长度。

 1 int start = 0;//起始位置
 2 int end = 0;//结束位置
 3 int max = 0;
 4 for(int i = 1; i <= n; ++i)
 5 {
 6     int sum = 0;
 7     for(int j = i; j <= n;++j)
 8     {
 9         sum += a[j];
10         if(sum > max)
11         {
12            start = i;
13            end = j;
14            max = sum;
15         }
16     }
17 }

  2.分治法

    求子区间及最大和,从结构上是非常适合分治法的,因为所有子区间[start, end]只可能有以下三种可能性:

      1.在[1, n/2]这个区域内
      2.在[n/2+1, n]这个区域内
      3.起点位于[1,n/2],终点位于[n/2+1,n]内

    以上三种情形的最大者,即为所求. 前两种情形符合子问题递归特性,所以递归可以求出. 对于第三种情形,则必然包括了n/2和n/2+1两个位置,这样就可以利用第二种穷举的思路分别向左右扩张求出:

 1 int maxInterval(int *a, int left, int right)
 2  {
 3     if(right==left)
 4       return a[left]>0?a[left]:0;
 5     int center = (left+right)/2;
 6     int leftMaxInterval = maxInterval(a,left,center);
 7     int rightMaxInterval= maxInterval(a,center+1,right);
 8     int sum = 0;
 9     int left_max = 0;
10     for(int i = center; i >= left; –i)
11     {
12        sum += a[i];
13        if(sum > left_max)
14           left_max = sum;
15 
16     }
17     sum = 0;
18     int right_max = 0;
19     for(int i = center+1; i <= right; ++i)
20     {
21        sum += a[i];
22        if(sum > right_max)
23          right_max = sum;
24     }
25     int res = left_max+right_max;
26     if(res < leftMaxInterval)
27         res = leftMaxInterval;
28     if(res < rightMaxInterval)
29         res = rightMaxInterval;
30     return res;
31  }

  3.动态规划并扩展到二维空间

    令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 #include<stdio.h>
 2  #include<string.h>
 3  int a[101][101],b[101],c[101];
 4  int subsequencesum(int a[],int n)
 5  {
 6      int sum=0,maxsum=-0x7fffff,i;
 7      for(i=1;i<=n;i++)
 8          if(maxsum<a[i])
 9              maxsum=a[i];
10      if(maxsum<=0)
11          return maxsum;
12      memset(c,0,sizeof(c));
13      for(i=1;i<=n;i++)
14      {
15             if(c[i-1]>0)
16                 c[i] = c[i-1] + a[i];
17             else
18                 c[i] = a[i];
19             if(c[i]>maxsum)
20                 maxsum=c[i]; 
21           /*      
22          sum+=a[i];
23          if(sum>maxsum)
24              maxsum=sum;   
25          else
26              if(sum<0)
27                  sum=0;
28             */
29      }
30      return maxsum;
31  }                     
32  int main()
33  {
34           int n,max,ans,temp;
35          int i,j,k,T,m;
36           while(~scanf("%d",&n))//说的是一组,实际却是多组 
37           {
38              temp=ans=max=-0x7fffff;
39              for(i=1;i<=n;i++)
40                  for(j=1;j<=n;j++)
41                      scanf("%d",&a[i][j]);
42              for(i=1;i<=n;i++)
43              {                         
44                      memset(b,0,sizeof(b));
45                      for(j=i;j<=n;j++)
46                      {
47                               for(k=1;k<=n;k++)
48                              {
49                                  b[k]+=a[j][k];
50                              }
51                              ans=subsequencesum(b,n);//算的是两列间的和, 
52                              if(temp<ans) 
53                                  temp=ans;
54                      }
55              }
56              printf("%d\n",temp);
57          }
58          //while(1);
59          return 0;
60  }

  为加深理解,这里推荐练习一下HDU 1081,还可以扩展到三维情况,有兴趣的读者请参看:最大长方体问题。

原文地址:https://www.cnblogs.com/hxsyl/p/2948435.html