[动规] P1103 书本整理

书本整理

题目描述

Frank是一个非常喜爱整洁的人。他有一大堆书和一个书架,想要把书放在书架上。书架可以放下所有的书,所以Frank首先将书按高度顺序排列在书架上。但是Frank发现,由于很多书的宽度不同,所以书看起来还是非常不整齐。于是他决定从中拿掉k本书,使得书架可以看起来整齐一点。

书架的不整齐度是这样定义的:每两本书宽度的差的绝对值的和。例如有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本书后的最小的不整齐度。

点击查看完整题目信息。

题解

用 dp[i][j] 表示:前 i 本书,选中 j 本书,并且第 i 本被选中,有最小不整齐度。

所以有状态转移方程:

f i , j = m i n ( f i , j , f p , j − 1 + ∣ w p − w i ∣ ) f_{i, j} = min(f_{i, j}, f_{p, j - 1} + \lvert w_{p} - w_{i} \rvert) fi,j=min(fi,j,fp,j1+wpwi∣),其中 j − 1 ⩽ p < i j-1\leqslant p < i j1p<i

代码(cpp):

#include<stdio.h>
#include<algorithm>
#include<string.h>

using namespace std;

struct book
{
  int h, w;
} books[101];

int cmp(book a, book b)
{
  return a.h > b.h;
}

int main()
{
  int n, k; // n 本书,去掉 k 本
  int m; // 还剩 m 本
  int i, j, p;
  int dp[101][101]; // dp[i][j],前 i 本选中 j 本
  int ans;

  scanf("%d %d", &n, &k);
  for (i = 0; i < n; ++ i)
    scanf("%d %d", &books[i].h, &books[i].w);

  sort(books, books + n, cmp);

  memset(dp, 0x3f, sizeof(dp)); // 每字节填充 0x3f

  for (i = 1; i < n + 1; ++ i)
    dp[i][1] = 0;

  m = n - k;

  for (i = 2; i < n + 1; ++ i) // 前 i 本
    for (j = 2; j < m + 1 && j < i + 1; ++ j) // 选中 j 本
      for (p = j - 1; p < i; ++ p) // 前 p 本选 j - 1 本
        dp[i][j] = min(dp[i][j], dp[p][j - 1] + abs(books[p - 1].w - books[i - 1].w));

  ans = dp[m][m];
  for (i = m + 1; i < n + 1; ++ i)
    ans = min(ans, dp[i][m]);
  printf("%d", ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值