华为OD机试_2025 B卷_书籍叠放(Python,200分)(附详细解题思路)

题目描述

书籍的长、宽都是整数对应 (l,w)。如果书A的长宽度都比B长宽大时,则允许将B排列放在A上面。现在有一组规格的书籍,书籍叠放时要求书籍不能做旋转,请计算最多能有多少个规格书籍能叠放在一起。

输入描述
输入:books = [[20,16],[15,11],[10,10],[9,10]]

说明:总共4本书籍,第一本长度为20宽度为16;第二本书长度为15宽度为11,依次类推,最后一本书长度为9宽度为10.

输出描述
输出:3

说明: 最多3个规格的书籍可以叠放到一起, 从下到上依次为: [20,16],[15,11],[10,10]

用例

输入 [[20,16],[15,11],[10,10],[9,10]]
输出 3

书籍叠放问题:最长严格递减子序列应用

核心解题思路

问题分析

题目要求找出能叠放在一起的最大书籍数量,规则是:

  1. 只有当书籍A的长宽都严格大于书籍B时,才能将B放在A上面
  2. 书籍不能旋转
  3. 需要找到一个书籍序列,使得序列中每个书籍的长宽都严格大于其后面的书籍

解决方案:排序+最长严格递减子序列

  1. 关键洞察:问题本质是寻找二维空间中的最长链,其中每个元素都严格大于链中下一个元素
  2. 排序预处理
  • 按长度降序排序(从大到小)
  • 长度相同时,按宽度降序排序(从大到小)
  1. 问题转化:排序后问题简化为在宽度序列中寻找最长严格递减子序列
  2. 高效算法:使用二分查找维护最小末尾序列,时间复杂度O(n log n)

完整代码实现

import bisect

def max_books(books):
    """
    计算最多能叠放的书籍数量
    
    参数:
    books: 二维列表,每个元素为[长, 宽]
    
    返回:
    最多能叠放的书籍数量
    """
    # 处理空输入
    if not books:
        return 0
    
    # 1. 对书籍进行排序:长度降序,长度相同则宽度降序
    books.sort(key=lambda x: (-x[0], -x[1]))
    
    # 2. 提取所有书籍的宽度
    widths = [book[1] for book in books]
    
    # 3. 寻找宽度序列的最长严格递减子序列
    tail = []  # 存储每种长度递减子序列的最小末尾值
    
    for w in widths:
        # 如果当前宽度小于tail的最后一个元素,直接添加
        if not tail or w < tail[-1]:
            tail.append(w)
        else:
            # 二分查找第一个大于等于w的位置
            idx = bisect.bisect_left(tail, w)
            # 用w替换该位置的元素
            tail[idx] = w
    
    return len(tail)

# 主程序
if __name__ == "__main__":
    # 读取输入
    import sys
    data = sys.stdin.read().strip()
    
    # 处理输入格式:"[[20,16],[15,11],[10,10],[9,10]]"
    if not data:
        print(0)
    else:
        # 删除两端的方括号
        data = data[2:-2]
        # 分割书籍数据
        book_strs = data.split('],[') if data else []
        books = []
        for s in book_strs:
            # 分割长宽
            parts = s.split(',')
            if len(parts) == 2:
                l = int(parts[0])
                w = int(parts[1])
                books.append([l, w])
        
        # 计算并输出结果
        result = max_books(books)
        print(result)

示例解析

示例1:输入[[20,16],[15,11],[10,10],[9,10]]

  1. 排序处理
  • 原始书籍:[20,16], [15,11], [10,10], [9,10]
  • 按长度降序:[20,16], [15,11], [10,10], [9,10](已有序)
  • 宽度序列:[16, 11, 10, 10]
  1. 构建tail序列
处理16: tail = [16]
处理11: 11<16 → tail = [16,11]
处理10: 10<11 → tail = [16,11,10]
处理10: 10>=10 → 替换第一个>=10的位置(tail[2]) → tail = [16,11,10]
  1. 结果:tail长度=3

示例2:输入[[10,20],[15,15],[16,10],[17,9]]

  1. 排序处理
  • 按长度降序:[17,9], [16,10], [15,15], [10,20]
  • 宽度序列:[9,10,15,20]
  1. 构建tail序列
处理9: tail = [9]
处理10: 10>=9 → 替换tail[0] → tail = [10]
处理15: 15>=10 → 替换tail[0] → tail = [15]
处理20: 20>=15 → 替换tail[0] → tail = [20]
  1. 结果:tail长度=1(只能选一本书)

示例3:输入[[5,4],[6,4],[6,7],[7,3]]

  1. 排序处理
  • 长度降序:[7,3], [6,7], [6,4], [5,4]
  • 长度相同时按宽度降序:[7,3], [6,7], [6,4], [5,4]
  • 宽度序列:[3,7,4,4]
  1. 构建tail序列
处理3: tail = [3]
处理7: 7>=3 → 替换tail[0] → tail = [7]
处理4: 4<7 → tail = [7,4]
处理4: 4>=4 → 替换第一个>=4的位置(tail[1]) → tail = [7,4]
  1. 结果:tail长度=2(如[6,7]和[5,4])

总结

关键要点

  1. 排序预处理
  • 按长度降序确保长度关系
  • 长度相同时按宽度降序避免冲突
  1. 问题转化
  • 二维问题转化为一维序列问题
  • 寻找最长严格递减子序列
  1. 二分优化
  • 维护最小末尾值序列
  • 保证序列的严格递减性

应用场景

  1. 俄罗斯套娃问题
  2. 装箱问题
  3. 任务调度依赖
  4. 资源分配优化
  5. 游戏物体堆叠系统

该解法通过巧妙的排序策略将二维问题转化为一维问题,再利用二分查找优化经典动态规划算法,高效解决了书籍叠放问题。算法在保证正确性的同时具有良好的时间复杂度,适用于大规模数据处理。

你可能感兴趣的:(华为OD机试Python版,华为od,python,算法)