二維dp數組java
dp[i][j]前j個數字選取i段的最大和,必定要第j個數字數組
dp[i][j]=dp[i][j-1]+a[j-1] 這是指把第j個數字併入前面那些數字的最後一段優化
dp[i][j]=Max(dp[i][j],dp[i-1][m]+a[j-1]) 這是把第j個數字單獨做爲一段spa
時間複雜度(O(k*n^2))code
public int max_M_sum(int[] a,int k) { int[][] dp=new int[k+1][a.length+1];//dp[i][j]前j個數字選取i段的最大和,必定包含第j個數字 dp[1][1]=a[0]; for(int i=2;i<k+1;i++) dp[i][i]=dp[i-1][i-1]+a[i-1]; for(int i=1;i<k+1;i++) { for(int j=i+1;j<a.length+1;j++) { dp[i][j]=dp[i][j-1]+a[j-1];//至關於把第j個數鏈接到前面的最後一段後面 for(int temp=i-1;temp<j;temp++) { dp[i][j]=Math.max(dp[i][j],dp[i-1][temp]+a[j-1]); } } } return dp[k][a.length];//這裏返回的不是最優解 }
觀察最上面的圖發現,dp[i][j]只由左邊的一位和上面的一段決定,並且是由上面一段的最大值決定的,所以能夠進行優化blog
時間複雜度O(k*n)get
public int max_M_sum(int[] a,int k) { int[] pre=new int[a.length+1];//pre[i]少一段的最大值,從1到i之間的最大值 int[] dp=new int[a.length+1]; int tmp=-999999; for(int i=1;i<k+1;i++) { tmp=-999999;//不斷刷新最左邊的那個空的 for(int j=i;j<a.length+1;j++) { dp[j] = Math.max(dp[j-1], pre[j-1])+a[j-1]; pre[j-1]=tmp; tmp=Math.max(tmp, dp[j]); } } return tmp; }
這個筆試題,最終的段數能夠小於k,求最大的就行,所以須要合併一下,減少複雜度,但仍是過不去,我也不知道爲何class
import java.util.*; public class Main{ public static void main(String[] args) { Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int k=sc.nextInt(); int[] a=new int[n]; for(int i=0;i<n;i++) { a[i]=sc.nextInt(); } int t=0; int[] b=new int[n]; b[0]=a[0]; for(int i=1;i<n;i++) { if(a[i]*a[i-1]>0) {//同號 b[t]+=a[i]; } else { t++; b[t]=a[i]; } } Main m=new Main(); System.out.println(m.max_M_sum(b,k,t+1)); } public int max_M_sum(int[] a,int k,int t) { if(t<=k) { int res=0; for(int i=0;i<t;i++) { if(a[i]>0) res+=a[i]; } return res; } else{ int[] pre=new int[t+1];//少一段的最大值,不必定包含最後一個 int[] dp=new int[t+1]; int tmp=-999999; int res=Integer.MIN_VALUE; for(int i=1;i<k+1;i++) { tmp=Integer.MIN_VALUE;//不斷刷新最左邊的那個空的 for(int j=i;j<t+1;j++) { dp[j] = Math.max(dp[j-1], pre[j-1])+a[j-1]; pre[j-1]=tmp; tmp=Math.max(tmp, dp[j]); } } for(int i=0;i<t+1;i++) res=Math.max(res, dp[i]); return res; } } }