一、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