【算法筆記第11.2節-動態規劃】問題 A: 最大連續子序列

問題 A: 最大連續子序列

時間限制: 1 Sec  內存限制: 32 MB
提交: 380  解決: 170
[提交][狀態][討論版][命題人:外部導入]

題目描述

給定K個整數的序列{ N1, N2, ..., NK },其任意連續子序列可表示爲{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大連續子序列是所有連續子序列中元素和最大的一個,例如給定序列{ -2, 11, -4, 13, -5, -2 },其最大連續子序列爲{ 11, -4, 13 },最大和爲20。現在增加一個要求,即還需要輸出該子序列的第一個和最後一個元素。

輸入

測試輸入包含若干測試用例,每個測試用例佔2行,第1行給出正整數K( K<= 10000 ),第2行給出K個整數,中間用空格分隔,每個數的絕對值不超過100。當K爲0時,輸入結束,該用例不被處理。

輸出

對每個測試用例,在1行裏輸出最大和、最大連續子序列的第一個和最後一個元素,中間用空格分隔。如果最大連續子序列不唯一,則輸出序號i和j最小的那個(如輸入樣例的第2、3組)。若所有K個元素都是負數,則定義其最大和爲0,輸出整個序列的首尾元素。

樣例輸入

5
-3 9 -2 5 -4
3
-2 -3 -1
0

樣例輸出

12 9 5
0 -2 -1

提示

 

 


這是一道稍微有點難度的動態規劃題。

 


首先可以想到的做法是枚舉每個區間的和,預處理sum[i]來表示區間[1, i]的和之後通過減法我們可以O(1)時間獲得區間[i, j]的和,因此這個做法的時間複雜度爲O(n^2)。

 


然後這題的數據範圍較大,因此還需作進一步優化纔可以AC。記第i個元素爲a[i],定義dp[i]表示以下標i結尾的區間的最大和,那麼dp[i]的計算有2種選擇,一種是含有a[i-1],一種是不含有a[i-1],前者的最大值爲dp[i-1]+a[i],後者的最大值爲a[i]。而兩者取捨的區別在於dp[i-1]是否大於0。

#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long int LL;
int a[10001];
int dp[10001];
int main()
{
   int n;
   while(scanf("%d",&n)!=EOF)
   {
       if(n==0) break;
       for(int i=0; i<n; i++)
        scanf("%d",&a[i]);
       dp[0] = a[0];//邊界條件
       int ans = dp[0], left=0, right=0;
       for(int i=1; i<n; i++)
       {
          dp[i] = max(dp[i-1]+a[i], a[i]);
          if(dp[i]>ans)
          {
              ans = dp[i];
              right = i;
          }
       }
       for(int i=right; ;i--)//找開始
       {
           ans-=a[i];
           if(ans==0)
           {
               left = i;
               break;
           }
       }
       if(dp[right]>=0)
            printf("%d %d %d\n",dp[right], a[left], a[right]);
       else
            printf("0 %d %d\n", a[0], a[n-1]);

   }

   return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章