1. 程式人生 > >杭州電子科技大學Online Judge 之 “最大連續子序列(ID1231)”解題報告

杭州電子科技大學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的同時更新記錄最大子序列邊界的變數maxRightmaxLeft就行了

為了能夠正確處理序列值為非正整數的情況,我們初始化maxSum = -1;

maxLeft = 0;

maxRight = n-1;

說明:

演算法思想:動態規劃。

資料結構:基本資料型別。

時間複雜度: O(N);

本題的姐妹題是“MaxSumID1003)”,演算法思想相同,輸出要求不同。

12390498

2014-12-04 13:59:52

Accepted

1231

62MS

256K

878 B

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

1231

124MS

1132K

1010 B

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]);
}