【区间 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]

备注:

扫描二维码关注公众号,回复: 11356173 查看本文章

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] 表示将前 j j 个数分成 i i 段的最大子弹和。
  • 思考初始化:
    • f [ 1... m ] [ 1... n ] = 0 f[1...m][1...n] = 0
  • 思考状态转移方程
    • i = j i = j ,则 f [ i ] [ j ] = f [ i 1 ] [ j 1 ] + a [ j ] f[i][j] = f[i-1][j-1] + a[j] 表示每个数字都可自己起一段。
    • i < j i < j ,则分为两种情况:
      • 在第 i i 段中加入第 j j 个数字: f [ i ] [ j ] = f [ i ] [ j 1 ] + a [ j ] f[i][j] = f[i][j-1] + a[j]
      • 从前面的 i 1 i-1 段中选一段,然后第 j j 个数字自己起一段: f [ i ] [ j ] = m a x ( f [ i 1 ] [ k ] ) + a [ j ] f[i][j] = max( f[i-1][k] ) + a[j] k [ i 1 , j ) k∈ [i-1, j) ,表示第 j j 个数字自己起一段。
  • 思考输出 m a x ( f [ m ] [ j ] ) j [ m , n ] max(f[m][j]),j∈[m,n] 表示将序列 [ 0 , j ] [0,j] 分为 m m 段,选择其中最大的一段。
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 × n 2 ) 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

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/106869125
今日推荐