最大m子段和總結與例題 51nod1052 HDU1024
阿新 • • 發佈:2019-01-23
最大m子段和
一、定義
給定由n個整數(可能為負)組成的序列a1、a2、a3...,an,
以及一個正整數m,要求確定序列的m個不相交子段,使這m個子段的總和最大!
特別注意:
有些題目可能不存在負數答案,給出的序列全是負數,那麼不管m是多少,答案是0。此時選擇的子段是0個,不足m個,但符合題意。。。
也可能有些題目要求,必須選夠m個子段。
區別在dp陣列的初始化。前者要求dp初始為0,後者要求第0行為0,其餘為負無窮
二、解題思路
動態規劃,藉助矩陣可以直觀的看到計算過程。 定義二維陣列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 基準時間限制: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 -2 11 -4 13 -5 6 -2Output示例26
【AC程式碼】:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+5; const int INF=0x3f3f3f3f; int n,m; ll a[N],dp[2][N]; //只儲存上一行和當前行 int main() { while(~scanf("%d%d",&n,&m)) //n個數字,m子段和 { for(int i=1;i<=n;i++) scanf("%lld",a+i); for(int i=0;i<=n;i++) dp[0][i]=0,dp[1][i]=0; //關鍵!此題答案只允許正值 for(int i=1,k=1;i<=m;i++,k^=1) //分為i段,k為兩行之間的切換 { dp[k][i-1]=-INF; //i==j時,杜絕與前一元素共伍 ll maxpre=-INF; //maxpre記錄上一行的最大值 for(int j=i;j<=n-m+i;j++) { maxpre=max(maxpre,dp[k^1][j-1]); //隨時更新上一行最大值 dp[k][j]=max(dp[k][j-1],maxpre)+a[j]; //*對情況1、2的選擇 } } ll ans=-INF; for(int i=m;i<=n;i++) //找到第m行的最大值,即為答案 ans=max(ans,dp[m&1][i]); printf("%lld\n",ans); } }
2、HDU 1024 http://acm.hdu.edu.cn/showproblem.php?pid=1024資料量比51nod的這個題大,一百萬。上面的程式碼,把n和m互換就可以過HDU1024