书本整理(含代码详解)

书本整理

题目描述

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 1n100,1k<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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java 猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值