杭州電子科技大學 Online Judge 之 “Max Sum PlusPlus(ID1024)”解題報告
杭州電子科技大學 Online Judge 之 “Max Sum PlusPlus(ID1024)”解題報告
Description:Max Sum Plus Plus
Now I think youhave got an AC in Ignatius.L's "Max Sum" problem. To be a braveACMer, we always challenge ourselves to more difficult problems.
Now you are facedwith a more difficult problem.
Given a consecutive number sequence S1, S2, S3, S4 ... Sx,... Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767).
We define a functionsum(i, j) = Si + ... + Sj (1 ≤ i ≤ j ≤ n).
Now given an integer m (m > 0), your task is to find mpairs of i and j
which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + ... +sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is notallowed).
But I`m lazy, I don't want to write a special-judge module,so you don't have to output m pairs of i and j,
just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead.^_^
Input
Each test case will begin with two integers m and n, followedby n integers S1, S2, S3 ... Sn.
Process to the end of file.
Output
Output the maximal summation described above in one line.
Sample Input
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
Sample Output
6
8
Hint
Huge input, scanf and dynamic programming is recommended.
蹩腳的翻譯:
題目描述:
現在我認為你已經在伊格內修斯·李的“最大和”問題中獲得了一個AC 。作為一個勇敢的ACMer,我們總是自我挑戰更困難的問題,現在你面對的是一個更難的問題。
給定一個連續整數序列S1, S2, S3, S4... Sx, ... Sn (1 ≤ x ≤ n ≤ 1,000,000,-32768 ≤ Sx ≤ 32767).
我們定義一個函式sum(i, j) = Si+ ... + Sj (1 ≤ i ≤ j ≤ n).
現在給出一個整數 m (m > 0),你的任務是找到m對i和j,使得sum(i1, j1) +sum(i2, j2) + sum(i3, j3) + ... + sum(im, jm) 最大,
其中 ix ≤ iy ≤ jx 或 ix ≤ jy ≤ jx 是不允許出現的。
但是我很懶,我不想寫一個專門的判斷模組,所以你不需要輸出m對i和j,而只需輸出sum(ix, jx)(1 ≤ x ≤ m)的最大值就行了。
輸入:
每個測試用例將以兩個整數m和n開始, 緊隨其後的是n個整數S1、S2、S3……Sn。直到讀入檔案結束。
輸出:
在一行上輸出題目描述中所說的最大值。
演算法分析:
本題是動態規劃演算法的典型應用。如果MAX值較小,我們可以使用一個二維陣列maxSum[MAX][MAX]來儲存所有將共j個元素分成i組所獲得的最大連續子序列之和,其中1<=j<=n,1<=i<=m。
但由於本題中的MAX=1000001,實在是太大了(實際只有把所有的陣列都設為全域性變數才能分配出這麼大的陣列空間)。所以必須模仿斐波那契數列中,不需要記錄所有的F[i]值,只需迭代記錄F[i-1]和F[i-2]就可以求得F[i]的方法,設定以下3個數組來迭代記錄中間結果。
int curSum[MAX];//用來儲存包含A[j]的最大連續子序列之和
int preSum[MAX];//用來儲存將共j個元素分成i-1組所獲得的最大連續子序列之和
int maxSum[MAX];//用來儲存將共j個元素分成i組所獲得的最大連續子序列之和。
演算法的基本思想是:以i和j分別作為外,內層迴圈變數,二者的規模都是從小到大,用maxSum[j]記錄將共j個元素分成i組所獲得的最大連續子序列之和。若將i個元素分成i組,則每個元素都要用上,此時maxSum[i] =curSum[i] = preSum[i-1] + A[i];
接下來不斷加入新的元素,即增加j的值,計算加入新元素後能否得到更大的連續子序列和。將curSum[j-1]和 preSum[j-1]進行比較,讓較大者和新元素A[j]求和,看看新的和是否會比maxSum[j-1]大,在maxSum[j]中儲存目前得到的最大值。
演算法的關鍵在於每輪計算結束都要把maxSum[]值複製到 preSum[] ,以便進行下一輪迭代計算。
說明:
演算法思想:動態規劃。
資料結構:陣列,基本資料型別。
時間複雜度: O(m*n);
“MaxSum(ID1003)”相當於本題中m==1的情況。
12423653 |
2014-12-07 19:51:06 |
Accepted |
717MS |
2672K |
C |
程式碼如下:
#include<stdio.h>
#include<stdlib.h>
#define MAX 1000001
int A[MAX];
int curSum[MAX];//用來儲存包含A[j]的最大連續子序列之和
int preSum[MAX];//用來儲存將共j個元素分成i-1組所獲得的最大連續子序列之和
int maxSum[MAX];//用來儲存將共j個元素分成i組所獲得的最大連續子序列之和
int MaxSubPlus(const int A[], int m, int n);//動態規劃記錄將共j個元素分成i組所獲得的最大連續子序列之和
int main(void)
{
int i, m, n;
while(scanf("%d%d",&m,&n)!=EOF)
{
for (i=1; i<=n;i++)
scanf("%d", &A[i]);
printf("%d\n", MaxSubPlus(A, m, n));
}
return 0;
}
//類似斐波那契數列,不需要記錄所有的F[i]值,只需迭代記錄F[i-1]和F[i-2]就可以求得F[i]
int MaxSubPlus(const int A[], int m, int n)//動態規劃記錄將共n個元素分成m組所獲得的最大連續子序列之和
{
int i, j;
for (j=0; j<=n; j++)//初始化
preSum[j] = 0;
for (i=1; i<=m; i++) //動態規劃,規模從小到大,用maxSum[j]記錄將共j個元素分成i組所獲得的最大連續子序列之和
{
maxSum[i] = curSum[i] = preSum[i-1] + A[i];//若將i個元素分成i組,則每個元素都要用上
for (j=i+1; j<=n; j++)
{
if (curSum[j-1] > preSum[j-1]) //curSum[j]儲存包含A[j]的i組最大連續子序列之和
curSum[j] = curSum[j-1] + A[j];
else
curSum[j] = preSum[j-1] + A[j];
maxSum[j] = (curSum[j] > maxSum[j-1]) ? curSum[j] : maxSum[j-1];
}
for (j=i; j<=n; j++) //把maxSum[]值複製到 preSum[] ,進行下一輪迭代計算
preSum[j] = maxSum[j];
}
return maxSum[n];
}