最大子段和算法分析


最大子段和問題(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,還可以擴展到三維情況,有興趣的讀者請參看:最大長方體問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM