1. 程式人生 > >【DP-最大子串和】PAT1007. Maximum Subsequence Sum

【DP-最大子串和】PAT1007. Maximum Subsequence Sum

Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1 <= i <= j <= K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (<= 10000). The second line contains K numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:

10 1 4

/*
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
分析:
    首先,既然要記錄最大和序列的開始位置、結束位置、最大和以及當前序列的開始位置、結束位置、當前和(不包括當前數),
                        則分別定義ansst,ansend,ansmax,                    curst,curend,cursum;
                        初始化:當前的和=0;
          (剛開始不知道這幾個變數初始化為多少,先看測試資料;)
    接下來,看策略:
      1、-10
            當前和=0,當前數=-10,因為當前和+當前數=-10<0【4】,顯然不可取,因此,我們把當前和=0,當前的開始位置置於下一個下標;
      2、1 2 3 4
             這些數都是正數【1】,因此,肯定是可取的,這時,就要記錄當前結束位置(因為開始位置在第一個數-10的時候已經記錄過了,所以不必記錄)
             當前和累加;因為當前和>最大和,因此,最大和序列的開始,結束位置以及最大和都要更新;
      3、-5
             負數,顯然,這裡我們不能去更新最大和序列的一些屬性(因為無法判斷,但是之前的1,2,3,4序列已經被儲存),
             注意:1+2+3+4(當前最大和)+(-5)>0【3】,因此,
             所以,這裡我們要更新的是當前序列的一些屬性,結束位置要更新,當前和肯定也要記錄(因為可能後面有一個超大正數);
      4、-23
             此時,cursum=1+2+3+4-5=5,5+(-23)<0【4】,因此,如果加入-23,顯然沒有之前的大,
             而且如果後面有個超大正數,也不可能加上前面的序列(因為他的和是個負數,起了一個削減的作用),因此採用和步驟1相同的策略;
      5、3
             此時,ansmax=10,cursum=0,curst=7(下標),0+7<10【2】,因此,還無法“動搖”最大和序列,但是,我們已經開始記錄結束位置了;
      6、7
             cursum=3+7=10,10<=10,按照題意,不更新最大和序列,因此,還是選擇【2】策略;
      7、-21
             cursum=10-21<0【4】
     經過以上的分析,我們就能寫出相應的程式碼,這時,還有一個問題,就是變數初始化的問題:
              如果有這麼一組測試資料:
              4
              -1 -2 0 -1
              按照題意顯然應該輸出:
              0 0 0
              因此,在當前數為0時,我們應該去更新最大和序列,也就是當前和>最大和【1】,故,ansmax設為負數
              再看一組:
              2
              100 10
              顯然剛開始就要更新最大和序列,而最大和序列的屬性值來源於當前和序列,因此,當前和序列的所有引數值必須全部進行初始化為0;
    若當前數為非負數,且加上當前和>最大和,則:1、當前和+=當前數;2、更新最大和序列;                 【1】
                    且加上當前和<=最大和,則:1、當前和+=當前數;2、更新當前序列的結束位置;          【2】
    若當前數為負數,且當前和+當前數>0,則:1、當前和+=當前數;2、更新當前序列的結束位置;             【3】                               
                    且當前和+當前數<0,則:1、當前和=0;2、更新當前序列的開始位置為下一個下標         【4】
    注:這裡為什麼負數就要和0進行比較,因為加上一個負數,和肯定是減小的,也就是說之前的最大和序列的屬性值已經被儲存。
*/

#include<iostream>
#include<stdio.h>
using namespace std;

#define INF 0x7fffffff

int max(int a,int b)
{
    return a>b?a:b;
}

int data[10002];

int main()
{
    int i;
    int n;
    int curst,curend,cursum;
    int ansst,ansend,ansmax;
    cursum=curst=curend=0;
    ansmax=-1;
    bool flag=true;
    scanf("%d",&n);
    for(i=0;i<n;++i)
    {
        scanf("%d",&data[i]);
        if(data[i]>=0)
        {
            flag=false;
        }
    }
    if(flag)                     //全部都是負數
    {
        printf("0 %d %d\n",data[0],data[n-1]);
        return 0;
    }
    for(i=0;i<n;++i)
    {
        if(data[i]>=0)
        {
            if(cursum+data[i]>ansmax)
            {
                ansst=curst;
                ansend=curend=i;
                ansmax=cursum+data[i];
                cursum+=data[i];
            }        
            else
            {
                cursum+=data[i];
                curend=i;
            }
        }
        else
        {
            if(cursum+data[i]>0)
            {
                cursum+=data[i];
                curend=i;
            }
            else
            {
                curst=i+1;
                cursum=0;
            }
        }
    }
    printf("%d %d %d\n",ansmax,data[ansst],data[ansend]);
    return 0;
}