P5760
容易想到设 $f_{i, j}$ 表示前 $i$ 块积木,把它们分成 $j$ 堆柱子后高度之和的最大值 (第 $i$ 块积木在第 $j$ 堆柱子),
然后考虑第 $i$ 块三种情况:
-
不放,什么都不用做
-
另起一个柱子,枚举第 $j - 1$ 堆柱子的顶端 $k$,则
$$f_{i, j} = \max(f_{i, j}, f_{k, j - 1} + high_i)$$
-
加在前一个柱子之前,枚举第 $i$ 块积木在第 $k$ 块积木上,则
$$f_{i, j} = \max(f_{i, j}, f_{k, j} + high_i)$$
其中,$high_i$ 为第 $i$ 块积木的高度,
高高兴兴地写完,交!听取 WA 声一片啊!
仔细想想:长方体可以通过旋转得到另一个长方体!
一个长方体可以最多可以 $3$ 个不同的长方体,
令类型 $0$ 为以 $a, b$ 为底的长方体,
类型 $1$ 为以为底的 $b, c$ 长方体,
类型 $2$ 为以 $c, a$ 为底的长方体
其中,$a, b, c$ 为题目中的意思,
设 $f_{i, j, d}$ 表示前 $i$ 块积木,把它们分成 $j$ 堆柱子,第 $i$ 块积木类型为 $d$,的高度之和的最大值 (第 $i$ 块积木在第 $j$ 堆柱子)
这里 $0 \leq d \leq 2$,
同上,分三种情况:
-
不放,什么都不用做
-
另起一个柱子,枚举第 $j - 1$ 堆柱子的顶端 $k$,则
$$f_{i, j, d1} = \max(f_{i, j, d1}, f_{k, j - 1, d2} + high_{i, d1})$$
-
加在前一个柱子之前,枚举第 $i$ 块积木在第 $k$ 块积木上,则
$$f_{i, j, d1} = \max(f_{i, j, d1}, f_{k, j, d2} + high_{i,d1})$$
其中,$d1, d2$ 分别为 $i$ 的类型和 $k$ 的类型,$high_{i, d1}$ 为 $i$ 为 $d1$ 类型时的高度。
以下优化为 @asdfo123 大佬的方法:
为了方便,令 $l_{i,0},l_{i,1},l_{i,2}$ 分别为题目所说的 $a, b, c$,
在令$$l_{i, 3} = l_{i, 0}$$
$$l_{i, 4} = l_{i, 1}$$
则类型为 $d$ 的第 $i$ 个长方体的高为 $l_{i, d +2}$,长宽为 $l_{i, d}$ 以及 $l_{i, d + 1}$,
这样在 $high_{i, d}$ 时和处理两个长方体堆在一起时是否合法就方便多了。
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 110;
int l[N][5], f[N][N][5];
int length (int x, int d) { // 计算第 x 个长方体 d 类型的长方体的长
return max (l[x][d], l[x][d + 1]);
}
int width (int x, int d) { // 计算第 x 个长方体 d 类型的长方体的宽
return min (l[x][d], l[x][d + 1]);
}
bool check (int x, int d1, int y, int d2) { // 判断上下放置是否合法
return (length (x, d1) <= length (y, d2)) && (width (x, d1) <= width (y, d2));
}
int main() {
int n, m; scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf ("%d%d%d", &l[i][0], &l[i][1], &l[i][2]);
l[i][3] = l[i][0]; l[i][4] = l[i][1];
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
for (int k = 0; k < i; ++k) {
for (int d1 = 0; d1 <= 2; ++d1) {
for (int d2 = 0; d2 <= 2; ++d2) {
f[i][j][d1] = max (f[i][j][d1], f[k][j - 1][d2] + l[i][d1 + 2]); // 另起一堆柱子
if (check (i, d1, k, d2)) {
f[i][j][d1] = max (f[i][j][d1], f[k][j][d2] + l[i][d1 + 2]); // 放在在以前的柱子上面
}
ans = max (ans, f[i][j][d1]);
}
}
}
}
}
printf ("%d", ans);
return 0;
}
浙公网安备 33010602011771号