杭州電子科技大學Online Judge 之 “最大連續子序列(ID1231)”解題報告
杭州電子科技大學Online Judge 之 “最大連續子序列(ID1231)”解題報告
Problem Description
給定K個整數的序列{ N1, N2, ..., NK },其任意連續子序列可表示為{ Ni, Ni+1, ...,
Nj },其中 1 <= i <= j <= K。最大連續子序列是所有連續子序列中元素和最大的一個,
例如給定序列{ -2,11, -4, 13, -5, -2 },其最大連續子序列為{ 11, -4, 13 },最大和
為20。
在今年的資料結構考卷中,要求編寫程式得到最大和,現在增加一個要求,即還需要輸出該
子序列的第一個和最後一個元素。
Input
測試輸入包含若干測試用例,每個測試用例佔2行,第1行給出正整數K( < 10000 ),第2行給出K個整數,中間用空格分隔。當K為0時,輸入結束,該用例不被處理。
Output
對每個測試用例,在1行裡輸出最大和、最大連續子序列的第一個和最後一個元
素,中間用空格分隔。如果最大連續子序列不唯一,則輸出序號i和j最小的那個(如輸入樣例的第2、3組)。若所有K個元素都是負數,則定義其最大和為0,輸出整個序列的首尾元素。
Sample Input
6
-2 11 -4 13 -5 -2
10
-10 1 2 3 4 -5 -23 3 7 -21
6
5 -8 3 2 5 0
1
10
3
-1 -5 -2
3
-1 0 -2
0
Sample Output
20 11 13
10 1 4
10 3 5
10 10 10
0 -1 -2
0 0 0
演算法分析:
本題是動態規劃演算法的典型應用。有兩種方法來實現動態規劃演算法。
演算法1:
使用變數sum累計當前連續子序列之和,只要sum>=0,就不停累計下去,並把最大連續子序列之和記錄到maxSum中。如果sum小於0了,則將sum歸零,重新開始。
題目要求輸出該子序列的第一個和最後一個元素,我們只需要在更新maxSum的同時更新記錄最大子序列邊界的變數maxRight和maxLeft就行了。
為了能夠正確處理序列值為非正整數的情況,我們初始化maxSum = -1;
maxLeft = 0;
maxRight = n-1;
說明:
演算法思想:動態規劃。
資料結構:基本資料型別。
時間複雜度: O(N);
本題的姐妹題是“MaxSum(ID1003)”,演算法思想相同,輸出要求不同。
12390498 |
2014-12-04 13:59:52 |
Accepted |
62MS |
256K |
C |
演算法2:
設定一個輔助陣列S[MAX];用來儲存連續子序列的最大和。先取S[0] = A[0]; 如果S[i-1] > 0,則S[i] = S[i-1] + A[i]; 否則S[i] = A[i]; 即重新計算S[i]的值,相當於演算法1中的將sum歸零。
這樣遍歷陣列A,計算出所有S[i]。然後遍歷S[i],找出最大值,即最大連續子序列和,對應的下標i就是序列的右邊界right;從right往前遍歷,直到S[i] < 0,則左邊界left=i+1。
說明:
演算法思想:動態規劃。
資料結構:基本資料型別。
時間複雜度: O(N);
空間複雜度: O(MAX);
12399272 |
2014-12-05 14:14:37 |
Accepted |
124MS |
1132K |
C |
#include<stdio.h>
#include<malloc.h>
#include<math.h>
#define MAX 10000
void MaxSubsequenceSum(const int A[], int n);//動態規劃演算法
int main()
{
int A[MAX];
int k, i;
scanf("%d", &k);
while (k != 0)
{
for (i=0; i<k; i++)
{
scanf("%d", &A[i]);
}
MaxSubsequenceSum(A, k);//動態規劃演算法
scanf("%d", &k);
}
return 0;
}
//演算法1:
void MaxSubsequenceSum(const int A[], int n)//動態規劃演算法
{
int sum, maxSum, i, left, maxRight, maxLeft;
maxSum = -1;
sum = 0;
maxLeft = 0;
maxRight = n-1;
for (left=i=0; i<n; i++)
{
sum += A[i];
if (sum > maxSum)
{
maxSum = sum;
maxLeft = left;
maxRight = i;
}
else if (sum < 0) //連續子序列之和小於0了,則重新開始
{
sum = 0;
left = i + 1;
}
}
if (maxSum < 0)
maxSum = 0;
printf("%d %d %d\n", maxSum, A[maxLeft], A[maxRight]);
}
//演算法2:
void MaxSubsequenceSum(const int A[], int n)//動態規劃演算法
{
int S[MAX];//用來儲存連續子序列的最大和
int i, left, right;
S[0] = A[0];
for (i=1; i<n; i++)//儲存各連續子序列的最大和
{
if (S[i-1] > 0)
S[i] = S[i-1] + A[i];
else
S[i] = A[i];
}
for (right=i=0; i<n; i++)//查詢連續子序列的最大和的右邊界
{
if (S[i] > S[right])
right = i;
}
for (i=right; i>=0; i--)//查詢連續子序列的最大和的左邊界
{
if (S[i] < 0)
break;
}
left = i + 1;
if (S[right] < 0)//全部元素都是負數的情形
{
left = 0;
right = n - 1;
S[right] = 0;
}
printf("%d %d %d\n", S[right], A[left], A[right]);
}