1. 程式人生 > 實用技巧 >b_51_最大M欄位和(兩個狀態表示+兩種決策)

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();
    }
}