1. 程式人生 > >2086 Problem A 最大連續子序列

2086 Problem A 最大連續子序列

問題 A: 最大連續子序列

時間限制: 1 Sec  記憶體限制: 32 MB
提交: 198  解決: 93
[提交][狀態][討論版][命題人:外部匯入]

題目描述

給定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<iostream>
#include<algorithm>
using namespace std;
//這類簡單的實際上可不加陣列
int main() {
	int n;
	while (cin >> n&&n) {
		int a[10050], dp[10050];
		bool flag = true;
		for (int i = 0; i < n; i++) {
			cin >> a[i];
			if (a[i] > 0) flag = false;
		}
		if (flag) {
			cout << "0 " << a[0] << " " << a[n - 1] << endl;
			continue;
		}
		dp[0] = a[0];
		for (int i = 1; i < n; i++) {
			dp[i] = max(a[i], dp[i - 1] + a[i]);
		}
		int index = 0, num = 0;
		for (int i = 1; i < n; i++) {
			if (dp[i] > dp[index]) index = i;
		}
		for (int i = index; i >= 0; i--) {//尋找首元素下標
			num += a[i];
			if (num == dp[index]) {
				num = i;
				break;
			}
		}
		cout << dp[index] << " " << a[num] << " " << a[index] << endl;
	}
	return 0;
}