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