题目描述
0123456789
----------
111
111 333
11122333
11122333
2.如果当前行剩余宽度大于 0,并且小于下一张图片,则下一张图片会按比例缩放到宽度为当前行剩余宽度(高度向上取整),然后放入当前行。例如再放入一张 4x9 的图片,由于剩余宽度是 2,这张图片会被压缩到 2x5,再被放入第一行的末尾。此时该行高度为 5:
0123456789
---------
44
111 44
111 33344
1112233344
1112233344
3.如果当前行剩余宽度为 0,该工具会从下一行开始继续对剩余的图片进行排版,直到所有图片都处理完毕。此时所有行的总高度和就是这 N 张图片的排版高度。例如再放入 11x1, 5x5, 3x4 的图片后,效果如下图所示,总高度为 11:
0123456789
----------
44
111 44
111 33344
1112233344
1112233344
5555555555
66666
66666777
66666777
66666777
66666777
现在由于排版高度过高,图片的先后顺序也不能改变,小明只好从 N 张图片中选择一张删除掉以降低总高度。他希望剩余 N-1 张图片按原顺序的排版高度最低,你能求出最低高度是多少么?
输入描述
输出描述
一个整数,表示在删除掉某一张图片之后,排版高度最少能是多少。
输入输出样例
示例
输入
4 3
2 2
2 3
2 2
输出
2
运行限制
- 最大运行时间:2s
- 最大运行内存: 256M
总通过次数: 1291 | 总提交次数: 2444 | 通过率: 52.8%
难度: 困难 标签: 2017, 模拟, 省赛, 搜索
代码:
#include <bits/stdc++.h>
using namespace std;
const int MX = 1e5 + 5; // 定义数组的最大大小
int M, N; // M: 最大宽度, N: 物品数量
int w[MX], h[MX], t[MX]; // w[]: 物品宽度数组, h[]: 物品高度数组, t[]: 动态规划辅助数组
// 尝试将第i个物品附加到当前布局中
void attach(int i, int &W, int &H) {
if (W + w[i] > M) {
// 如果加上物品后超出最大宽度M,则按比例调整高度
H = max(H, static_cast<int>(ceil(1.0 * h[i] * (M - W) / w[i])));
} else {
// 否则直接更新高度
H = max(H, h[i]);
}
W = min(M, W + w[i]); // 更新当前布局宽度
}
// 计算从第i个物品开始到结束的最小高度和
int calc(int i, int W, int H) {
while (i < N && W < M) {
attach(i, W, H); // 尝试将第i个物品附加到布局中
i++;
}
return H + t[i]; // 返回加上从第i个物品开始的最小高度和
}
int main() {
scanf("%d%d", &M, &N); // 输入最大宽度M和物品数量N
for (int i = 0; i < N; i++) {
scanf("%d%d", &w[i], &h[i]); // 依次输入每个物品的宽度和高度
}
// 计算动态规划数组t[]
for (int i = N - 1; i >= 0; i--) {
t[i] = calc(i, 0, 0); // 计算从第i个物品开始的最小高度和,存入t[i]
}
int res = t[0]; // 初始化结果为从第0个物品开始的最小高度和
int tmp;
int pre_h = 0;
int W = 0, H = 0;
// 动态规划求解最小总高度和
for (int i = 0; i < N; i++) {
tmp = calc(i + 1, W, H); // 从第i+1个物品开始的最小高度和
res = min(res, pre_h + tmp); // 更新最小总高度和
attach(i, W, H); // 尝试将第i个物品附加到当前布局中
if (W == M) {
pre_h += H; // 如果当前布局达到最大宽度M,则将当前高度添加到总高度中
W = 0;
H = 0;
}
}
printf("%d\n", res); // 输出最小总高度和
return 0;
}