【區間 dp】A016_NK_善變的同伴(最大的m段字段和問題)

一、Problem

又到了喫午飯的時間,你和你的同伴剛剛研發出了最新的GSS-483型自動打飯機器人,現在你們正在對機器人進行功能測試。

爲了簡化問題,我們假設午飯一共有N個菜,對於第i個菜,你和你的同伴對其定義了一個好喫程度(或難喫程度,如果是負數的話……)A[i],

由於一些技(經)術(費)限制,機器人一次只能接受一個指令:兩個數L, R——表示機器人將會去打第L~R一共R-L+1個菜。

本着不浪費的原則,你們決定機器人打上來的菜,含着淚也要都喫完,於是你們希望機器人打的菜的好喫程度之和最大

然而,你善變的同伴希望對機器人進行多次測試(實際上可能是爲了多喫到好喫的菜),他想知道機器人打M次菜能達到的最大的好喫程度之和
當然,打過一次的菜是不能再打的,而且你也可以對機器人輸入-1, -1,表示一個菜也不打

輸入描述:

第一行:N, M

第二行:A[1], A[2], …, A[N]

輸出描述:

一個數字S,表示M次打菜的最大好喫程度之和

輸入
7 2
1 2 3 -2 3 -10 3
輸出
10
說明
[1 2 3 -2 3] -10 [3]

備註:

N <= 10^5 = 100000
|A[i]| <= 10^4 = 10000
10%數據M = 1
50%數據M <= 2
80%數據M <= 100
100%數據M <= 10^4 = 10000

二、Solution

方法一:暴力 dp(超時)

  • 定義狀態
    • f[i][j]f[i][j] 表示將前 jj 個數分成 ii 段的最大子彈和。
  • 思考初始化:
    • f[1...m][1...n]=0f[1...m][1...n] = 0
  • 思考狀態轉移方程
    • i=ji = j,則 f[i][j]=f[i1][j1]+a[j]f[i][j] = f[i-1][j-1] + a[j] 表示每個數字都可自己起一段。
    • i<ji < j,則分爲兩種情況:
      • 在第 ii 段中加入第 jj 個數字:f[i][j]=f[i][j1]+a[j]f[i][j] = f[i][j-1] + a[j]
      • 從前面的 i1i-1 段中選一段,然後第 jj 個數字自己起一段:f[i][j]=max(f[i1][k])+a[j]f[i][j] = max( f[i-1][k] ) + a[j]k[i1,j)k∈ [i-1, j),表示第 jj 個數字自己起一段。
  • 思考輸出max(f[m][j])j[m,n]max(f[m][j]),j∈[m,n]表示將序列 [0,j][0,j] 分爲 mm 段,選擇其中最大的一段。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
    static class Solution {
        void init() {
            Scanner sc = new Scanner(new BufferedInputStream(System.in));
            int n = sc.nextInt(), m = sc.nextInt(), a[] = new int[n+1], f[][] = new int[m+1][n+1];
            for (int i = 1; i <= n; i++) a[i] = sc.nextInt();

            for (int i = 1; i <= m; i++)
            for (int j = i; j <= n; j++) {
                if (i == j) 
                	f[i][j] = f[i-1][j-1] + a[j];
                else {
                    f[i][j] = f[i][j-1] + a[j];
                    for (int k = i-1; k < j; k++)
                        f[i][j] = Math.max(f[i][j], f[i-1][k] + a[j]);
                }
            }
            int max = 0;
            for (int j = m; j <= n; j++) {
                max = Math.max(max, f[m][j]);
            }
            System.out.println(max);
        }
    }
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
        s.init();
    }
}

複雜度分析

  • 時間複雜度:O(m×n2)O(m × n^2)
  • 空間複雜度:O(m×n)O(m × n)

方法二:滾動數組優化


複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()

  • https://blog.csdn.net/qq_22238021/article/details/78863701
  • 24贊:https://blog.csdn.net/winter2121/article/details/72848482
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章