2.11

2.11

P1775 石子合并(弱化版) - 洛谷 (luogu.com.cn)

  • 可以说是区间dp入门的基本题目了

  • 状态数组\(dp[i][j]\)为区间i到j合并后的消耗最小值

  • 那么我们只需要枚举区间长度,区间起点(区间末可以通过前面两个算出),再枚举区间中间的隔断点,即可得出最大值

  • 我们用前缀和来维护我们合并时的损耗

import java.io.*;
import java.util.*;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    //static Scanner cin = new Scanner(System.in);
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static final int N = (int) (3e2 + 10);
    static int[][] dp = new int[N][N];
    static int[] sum = new int[N];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

//    public static String next() throws IOException {
//        return cin.next();
//    }




    @Override
    public void run() {
        try {
           n = nextInt();
           for (int i = 1; i <= n; i++) {
               Arrays.fill(dp[i], 0x3f3f3f3f);
           }
           for (int i = 1; i <= n; i++) {
               int x = nextInt();
               dp[i][i] = 0;
               sum[i] = sum[i - 1] + x;
           }

           for (int len = 2; len <= n; len++) {
               for (int start = 1; start + len - 1 <= n; start++) {
                   int end = start + len - 1;
                   for (int k = start; k < end; k++) {
                       dp[start][end] = Math.min(dp[start][end], dp[start][k] + dp[k + 1][end] + sum[end] - sum[start - 1]);
                   }
               }
           }

           cout.println(dp[1][n]);
           cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

[P1880 NOI1995] 石子合并 - 洛谷 (luogu.com.cn)

  • 本题变式为环,其实本质和上题没有区别
  • 我们只需要将数组连接成两个数组,例如数组\([1, 2, 3, 4]\)变为数组\([1,2,3,4,1,2,3,4]\)我们会发现在维持长度\(len<=n\)时,其区间是符合其为环的情况的
  • 所以只需要枚举起点时由\(n->2n\)即可
import java.io.*;
import java.util.*;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    //static Scanner cin = new Scanner(System.in);
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static final int N = (int) (1e2 + 10);
    static int[][] dp = new int[N * 2][N * 2];
    static int[][] dp_ = new int[N * 2][N * 2];
    static int[] sum = new int[N * 2];
    static int[] arr = new int[N * 2];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

//    public static String next() throws IOException {
//        return cin.next();
//    }




    @Override
    public void run() {
        try {
           n = nextInt();
           for (int i = 1; i <= n * 2; i++) {
               Arrays.fill(dp[i], 0x3f3f3f3f);
           }
           for (int i = 1; i <= n; i++) {
               arr[i] = nextInt();
               arr[n + i] = arr[i];

           }

           for (int i = 1; i <= n * 2; i++) {
               sum[i] = sum[i - 1] + arr[i];
               dp[i][i] = 0;
           }

           for (int len = 2; len <= n; len++) {
               for (int start = 1; start + len - 1 <= n * 2; start++) {
                   int end = start + len - 1;
                   for (int k = start; k < end; k++) {
                       dp[start][end] = Math.min(dp[start][end], dp[start][k] + dp[k + 1][end] + sum[end] - sum[start - 1]);
                       dp_[start][end] = Math.max(dp_[start][end], dp_[start][k] + dp_[k + 1][end] + sum[end] - sum[start - 1]);
                   }
               }
           }

           int ans_min = 0x3f3f3f3f;
           int ans_max = 0;
           for(int i = 1; i <= n; i++) {
               ans_max = Math.max(ans_max, dp_[i][i + n - 1]);
               ans_min = Math.min(ans_min, dp[i][i + n - 1]);
           }
           cout.println(ans_min);
           cout.println(ans_max);
           cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

[P1063 NOIP 2006 提高组] 能量项链 - 洛谷 (luogu.com.cn)

  • 只是题目长了一点而已,本质上还是和环形dp没有多大区别
  • 难点就是在于每次合并的\(n*m*t\)怎么计算,我们可以发现规律就是当前区间起点的头标记*当前区间末尾点的尾标记*k(区间中的隔断点)的尾结点即可
package shuati;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    //static Scanner cin = new Scanner(System.in);
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static final int N = (int) (1e2 + 10);
    static zhuZi[] zhuZis = new zhuZi[N * 2];
    static int[][] dp = new int[N * 2][N * 2];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

//    public static String next() throws IOException {
//        return cin.next();
//    }




    @Override
    public void run() {
        try {
           n = nextInt();
           for (int i = 1; i <= n * 2; i++) zhuZis[i] = new zhuZi();
           for (int i = 1; i <= n; i++) {
                int x = nextInt();
                zhuZis[i].pre = x;
                if (i > 1) zhuZis[i - 1].tail = x;
                if (i == n) zhuZis[i].tail = zhuZis[1].pre;
           }
           for (int i = 1; i <= n; i++) zhuZis[i + n] = zhuZis[i];


           for (int len = 2; len <= n; len++) {
               for(int start = 1; start + len - 1 <= n * 2; start++) {
                   int end = start + len - 1;
                   for (int k = start; k < end; k++) {
                       int num = zhuZis[start].pre * zhuZis[end].tail * zhuZis[k].tail;
                       dp[start][end] = Math.max(dp[start][end], dp[start][k] + dp[k + 1][end] + num);
                   }
               }
           }

           int ans = 0;
           for (int i = 1; i <= n; i++) {
               ans = Math.max(ans, dp[i][n + i - 1]);
           }

           cout.println(ans);
           cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    static class zhuZi {
        int pre;
        int tail;
    }
}
posted @ 2025-02-11 22:49  Mikkeykarl  阅读(14)  评论(0)    收藏  举报