b_51_最大M字段和(两个状态表示+两种决策)

将给定的N个数划分为互不相交的M个子段,并且这M个子段的和是最大的

思路
f[i][j]表示将前i个数划分成j段后的最大和,下面是决策:

  • f[i-1][j]:将a[j]接在第j段后面
  • f[k][j-1]:a[j]另起一段,但因为加上只有a[j]这单独的一段后已经一共有j段了,所以需要从前f[k][j-1]中选j-1段最大的(k∈[i-1,j)),但前i-1段必须每段都要有一个数字把,所以k最小取i-1

注:并不需要用完n个数哦,但还是超时了啊

import java.util.*;
import java.math.*;
import java.io.*;
class Solution {
    int n,m;
    long a[],f[][];
    void init() throws IOException {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        n=sc.nextInt(); m=sc.nextInt(); a=new long[n+5]; f=new long[n+5][m+5];
        for (int i=1; i<=n; i++) a[i]=sc.nextLong();
        if (m>=n) {
            long s=0; for (int i=1; i<=n; i++) s+=a[i];
            System.out.println(s);
        } else {
            long mx=0;
            for (int j=1; j<=m; j++)
            for (int i=1; i<=n; i++) {
                f[i][j]=Math.max(f[i][j], f[i-1][j]+a[i]);
                for (int k=j-1; k<i; k++) //第i个数自己起一段,从(j-1,i-1)个数中选j-1段
                    f[i][j]=Math.max(f[i][j], f[k][j-1]); 
                mx=Math.max(mx, f[i][j]);
            }
            System.out.println(mx);
        }
    }
}
public class Main{
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
        s.init();
    }
}

最里面那层循环其实省去的,为什么?因为每次它的起始位置是j-1,终点是随着i的增加而增加,所以可作出等价变换

import java.util.*;
import java.math.*;
import java.io.*;
class Solution {
    int n,m;
    long a[],f[][];
    void init() throws IOException {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        n=sc.nextInt(); m=sc.nextInt(); a=new long[n+5]; f=new long[n+5][m+5];
        for (int i=1; i<=n; i++) a[i]=sc.nextLong();
        if (m>=n) {
            long s=0; for (int i=1; i<=n; i++) s+=a[i];
            System.out.println(s);
        } else {
            long mx=0;
            for (int j=1; j<=m; j++) {
                long t=0;
                for (int i=1; i<=n; i++) {
                    f[i][j]=Math.max(f[i][j], f[i-1][j]+a[i]);
                    if (i>=j) {
                        t=Math.max(t, f[i-1][j-1]); //这里不就是f[k][j-1]吗,只不过k每次都<i且≥j-1
                        f[i][j]=Math.max(f[i][j], t+a[i]);
                    }
                    mx=Math.max(mx, f[i][j]);
                }
            }
            System.out.println(mx);
        }
    }
}
public class Main{
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
        s.init();
    }
}

原文地址:https://www.cnblogs.com/wdt1/p/13891354.html