51nod 1052 最大m子段和 DP

2021-08-10 08:42:39 字數 2147 閱讀 2482

給定由n個整數(可能為負)組成的序列a1、a2、a3...,an,

以及乙個正整數m,要求確定序列的m個不想交子段,使這m個子段的總和最大!

動態規劃,借助矩陣可以直觀的看到計算過程。

定義二維陣列dp, dp[ i ][ j ],表示前 j 項所構成 i 子段的最大和,且必須包含著第j項,即以第j項結尾

然後是乙個遞推過程。

求dp[ i ][ j ],有兩種情況

1、dp[ i ][ j ] = dp[ i ] [ j-1 ] + a[ j ] ,即把第j項融合到第 j-1 項的子段中,子段數沒變

2、dp[ i ][ j ] = dp[ i-1 ] [ t ] + a[ j ],(i-1<= t < j )

把第 j 項作為單獨的乙個子段,然後找一下i-1個子段時,最大的和,然後加上a[ j ] 

然後比較上面兩種情況,取大的。

下面看圖,紅色數字為輸入的序列:

如圖,要求dp[ 3 ][ 6 ],只需比較他左邊的那個,和上面那一行圈起來的之中最大的數,

再加上a[ j ] 即為dp[ 3 ][ 6 ] 的值。

優化一下:

1、沿著第m行的最後乙個元素,往左上方向畫一條線,線右上方的元素是沒必要計算的

那麼dp[ i ][ j ] ,j++的時候,j的上限為 i + n - m 即可。

還有左下角那一半矩陣,也是不用計算的,因為1個數字不可能分為2個子段

2、每確定乙個dp[ i ][ j ],只需用到本行和上一行,所以不用開維陣列也可以,省記憶體。

開兩個一維陣列,pre和dp,pre記錄上一行,dp記錄當前行

3、再對上一行紅圈中的數字找最大值時,若用乙個迴圈來找,容易超時。

優化方法:在每次計算dp之前,同時記錄下j前面的最大元素。

時間複雜度大致為o(m*(n-m+1)),mn-m方

通過,分析情況1和2,就能發現,從左上角走到第 m 行的最後乙個元素即可,找出第 m 行的最大值即為答案。

詳見例題。

1、51nod 1052

1052 最大m子段和

基準時間限制:2 秒 空間限制:131072 kb 分值: 80 

難度:5級演算法題

n個整數組成的序列a[1],a[2],a[3],…,a[n],將這n個數劃分為

互不相交的m個子段,並且這m個子段的和是最大的。

如果m >= n個數中正數的個數,那麼輸出所有正數的和。

例如:-2  11 

-4 13 

-5 6 

-2,分為2段,11 -4 13一段,6

一段,和為26。

input

第1行:2個數n和m,中間用空格分隔。n為整數的個數,m為劃分為多少段。(2 <= n , m <= 5000)

第2 - n+1行:n個整數 (-10^9 <= a[i] <= 10^9)

output

輸出這個最大和
input示例

7 2

-211

-413-56

-2

output示例

26

【ac**】:

#include#includetypedef long long ll;

ll max(ll a,ll b)

int main()

return 0;

}

51Nod 1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。刷刷水有益身心健康。不過我還是沒有一眼看出來。考慮...

51Nod1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。input 第1行 2個數n和m,中間用空格分隔。...

51Nod 1052 最大M子段和

先將同符號的每一段存下來,並記錄前後段標號,將正數段總和記錄為tot 開乙個最小堆存每一段的abs值。每次從堆中取出乙個x 去掉這一段,並將左右的段與之合併再存入堆中,作為撤銷或更改操作。每次操作都會減少一段,直到段數 k就退出。include include include include def...