一、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(超時)
- 定義狀態:
- 表示將前 個數分成 段的最大子彈和。
- 思考初始化:
- 思考狀態轉移方程:
- ,則 表示每個數字都可自己起一段。
- ,則分爲兩種情況:
- 在第 段中加入第 個數字:
- 從前面的 段中選一段,然後第 個數字自己起一段:,,表示第 個數字自己起一段。
- 思考輸出:表示將序列 分爲 段,選擇其中最大的一段。
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();
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
方法二:滾動數組優化
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
- https://blog.csdn.net/qq_22238021/article/details/78863701
- 24贊:https://blog.csdn.net/winter2121/article/details/72848482