最大m子段和

2021-08-30 22:00:45 字數 2031 閱讀 3304

51nod - 1052 

題意描述:給定陣列a,長度為n。給定整數m,求不相交的m段字段和的最大值。

當m == 1 時:該問題就是最大子段和問題。

設dp[i]為以a[i]結尾的最大子段和,當我們考慮dp[i]的時候如果dp[i-1] > 0那麼肯定把a[i]接在後面最優,否則,取a[i]最優。

得到 dp[i] = max(dp[i-1]+a[i],a[i]);

這樣的話,問題是不是就明朗了呢?

int max = 0;

for(int i = 1; i <= n; i++)

容易看出來dp[i] 只和dp[i-1] 有關,因此記錄乙個last變數表示dp[i-1] 就能推出dp[i],所以並不需要開陣列的。

int last = 0,max = 0;

for(int i = 1; i <= n; i++)

若m不為1,那麼考慮給dp再加一維,表示段數。模擬一維的表述:

dp[i][j] 表示以a[j]結尾的i子段和的最優值。

考慮第j個元素:

若我們把a[j]接在在最後面一段裡,dp[i][j]可以表述為:x1 = dp[i][j-1]+a[j];

若我們讓a[j]自成一段,dp[i][j]可以表述為: x2 = max(dp[i-1][k])+a[j], 其中i-1 =< k <= j-1;

得到: dp[i][j] = max(x1,x2);

int ans = 0;

memset(dp,0,sizeof(dp);

for(int i = 1; i <= m; i++)

if(i == m) ans = max(ans,dp[i][j]);

}}

容易看出來 時間複雜度 o(m*n^2) 空間複雜度 o(m*n)

從上面容易看出來,其實在求dp[i][j] 時只用到了第i層與第i-1層,因此考慮用last陣列存上一層,dp存當前層減少空間開銷。

又注意到,其實第三層for迴圈其實是在求last陣列前幾項的最大值,因此可以直接處理好。

繼續優化:

ll ans = 0;

memset(dp,0,sizeof(dp));

memset(last,0,sizeof(last));

for(int i = 1; i <= m; i++)

for(int j = i; j <= n; j++)

}

容易看出來 時間複雜度 o(m*n) 空間複雜度 o(n)

#include using namespace std;

typedef long long ll;

const ll maxn = 5005;

const ll inf = 1e18;

ll dp[maxn],last[maxn];

ll a[maxn],b[maxn];

int main()

ll ans = 0;

memset(dp,0,sizeof(dp));

memset(last,0,sizeof(last));

for(int i = 1; i <= m; i++)

for(int j = i; j <= n; j++)

}cout << ans << endl;

return 0;

}

最大m子段和

最大m子段和問題 給定由n個整數 可能為負 組成的序列a1 a2 a3.an,以及乙個正整數m,要求確定序列的m個不想交子段,使這m個子段的總和最大!設b i,j 表示陣列a的前j項中i個子段和的最大值,並且第i個子段包含a j 1 i m,i j n 則所求的最優值為maxb m,j m j n ...

最大M子段和

最近掉入了dp的深淵,還附加數學知識,爽哉。在此分析一道提交了17次的dp n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 1...

最大m子段和

最大m子段和 定義一串子段s1,s2,s3 sn 1,sn 求m段不交叉最大子段和 解 設dp i j 代表前j個數分成i段的最大和 包括a j 狀態轉移方程 dp i j max dp i j 1 a j dp i 1 t a j i 1 解釋兩種狀態的最優解 a j 恰好在下一次最優解末項之後,...