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;
}
}
浙公网安备 33010602011771号