书本整理
题目描述
Frank 是一个非常喜爱整洁的人。他有一大堆书和一个书架,想要把书放在书架上。书架可以放下所有的书,所以 Frank 首先将书按高度顺序排列在书架上。但是 Frank 发现,由于很多书的宽度不同,所以书看起来还是非常不整齐。于是他决定从中拿掉k本书,使得书架可以看起来整齐一点。
书架的不整齐度是这样定义的:每两本书宽度的差的绝对值的和。例如有 4 4 4 本书:
1
×
2
1 \times 2
1×2
5
×
3
5 \times 3
5×3
2
×
4
2 \times 4
2×4
3
×
1
3 \times 1
3×1
那么 Frank 将其排列整齐后是:
1
×
2
1 \times 2
1×2
2
×
4
2 \times 4
2×4
3
×
1
3 \times 1
3×1
5
×
3
5 \times 3
5×3
不整齐度就是 2 + 3 + 2 = 7 2+3+2=7 2+3+2=7。
已知每本书的高度都不一样,请你求出去掉 k k k 本书后的最小的不整齐度。
输入格式
第一行两个数字 n n n 和 k k k,代表书有几本,从中去掉几本( 1 ≤ n ≤ 100 , 1 ≤ k < n 1 \le n \le 100, 1 \le k<n 1≤n≤100,1≤k<n)。
下面的 n n n 行,每行两个数字表示一本书的高度和宽度,均小于等于 200 200 200。
保证高度不重复
输出格式
一行一个整数,表示书架的最小不整齐度。
样例 #1
样例输入 #1
4 1
1 2
2 4
3 1
5 3
样例输出 #1
3
题目来源
洛谷
代码详解
#include<bits/stdc++.h>
using namespace std;
int n, k, m, Min = 0x7fffffff; // n是总书本数,k是要移除的书本数,m是剩下的书本数,Min记录最小的不整齐度
int f[501][501]; // f[i][l]:表示以第i本书结尾,选取了l本书时的不整齐度最小值
struct info {
int h, w; // 每本书的高度h和宽度w
} a[1001]; // 存储书本的数组
// 自定义比较函数:根据书本高度h从小到大排序
bool cmp(const info & x, const info & y) {
return x.h < y.h;
}
int main() {
// 读入书本总数n和移除书本数k
cin >> n >> k;
m = n - k; // 需要选择的书本数,即剩余的书本数m = n - k
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i].h, &a[i].w); // 读入每本书的高度h和宽度w
// 按书的高度从小到大排序,因为高度决定了书的顺序
sort(a + 1, a + n + 1, cmp);
// 初始化f数组,memset(f, 20, sizeof(f)) 将f数组中的每个元素设置为极大值,以便后续计算时可以通过min()函数缩小该值
memset(f, 20, sizeof(f));
// 选择单本书时没有不整齐度,因此对所有的f[i][1]赋值为0
for(int i = 1; i <= n; i++)
f[i][1] = 0;
// 遍历所有的书
for(int i = 2; i <= n; i++) { // 当前尝试放第i本书
for(int j = 1; j <= i - 1; j++) { // 尝试与前面的第j本书相邻
for(int l = 2; l <= min(i, m); l++) { // l表示当前组合的书本数量
// 尝试继承之前的组合,将其扩展到长度为l的组合
f[i][l] = min(f[i][l], f[j][l-1] + abs(a[i].w - a[j].w)); // 更新不整齐度,宽度差的绝对值越小越好
}
}
}
// 找出以m本书结尾的不整齐度最小值
for(int i = m; i <= n; i++)
Min = min(Min, f[i][m]); // 遍历所有可能的情况,取最小值
// 输出结果
printf("%d\n", Min);
return 0;
}