华为OD机试_2025 B卷_机房布局(Python,100分)(附详细解题思路)

题目描述

小明正在规划一个大型数据中心机房,为了使得机柜上的机器都能正常满负荷工作,需要确保在每个机柜边上至少要有一个电箱。
为了简化题目,假设这个机房是一整排,M表示机柜,I表示间隔,请你返回这整排机柜,至少需要多少个电箱。 如果无解请返回 -1 。

输入描述
cabinets = “MIIM”
其中 M 表示机柜,I 表示间隔

输出描述
2
表示至少需要2个电箱
备注 1 ≤ strlen(cabinets) ≤ 10000 其中 cabinets[i] = ‘M’ 或者 ‘I’

用例

输入MIIM
输出2
说明
输入MIM
输出1
说明
输入M
输出-1
说明
输入MMM
输出-1
说明
输入I
输出0
说明

数据中心机房电箱规划问题:简单贪心解法

核心解题思路

作为初学者,我们可能第一反应是暴力枚举所有可能放電箱的位置,但那样时间复杂度太高(O(2^n)),不适合长字符串。贪心算法是更好的选择:从左到右扫描字符串,每次遇到一个机柜('M')时,优先尝试用右边的间隔('I')来覆盖它,如果不行再用左边,否则就判定无解

为什么贪心有效?

  • 覆盖规则:每个电箱放在 'I' 上,可以覆盖左边和/或右边的 'M'。但每个 'M' 只需要被覆盖一次。
  • 贪心策略:从左到右扫描,保证每个 'M' 都被及时覆盖。优先用右边 'I' 覆盖,可以共享给后续 'M',从而最小化电箱数(例如 "MIM" 只需要一个电箱)。
  • 无效情况处理:如果某个 'M' 左边和右边都没有 'I',或者连续多个 'M' 没有间隔,则无解(如 "M""MMM")。

算法步骤:

  1. 初始化:计数器 count 记录电箱数,数组 placed 记录每个位置是否已放电箱(避免重复放置)。
  2. 扫描字符串:对每个字符:
    • 如果是 'I',跳过(我们只在遇到 'M' 时行动)。
    • 如果是 'M'
      • 检查是否已被覆盖(左边或右边已有电箱)。
      • 如果未被覆盖:
        • 优先尝试在右边放電箱(如果右边是 'I')。
        • 如果右边不行,尝试在左边放電箱(如果左边是 'I')。
        • 如果都不行,返回 -1
  3. 返回结果count 就是最少电箱数。

这个算法时间复杂度 O(n),只扫描一次字符串,非常高效。

代码实现

# 输入部分:读取字符串
cabinets = input().strip()

# 主体函数:计算最少电箱数
def min_electric_boxes(cabinets):
    n = len(cabinets)
    # 如果没有机柜,返回0
    if 'M' not in cabinets:
        return 0
    
    # 初始化:count记录电箱数,placed记录位置是否已放电箱
    count = 0
    placed = [False] * n  # placed[i]为True表示在i位置放电箱
    
    # 遍历每个字符
    for i in range(n):
        if cabinets[i] == 'M':  # 遇到机柜
            covered = False
            # 检查是否已被覆盖:左边或右边已有电箱
            if i - 1 >= 0 and cabinets[i-1] == 'I' and placed[i-1]:
                covered = True  # 左边有电箱覆盖
            if not covered and i + 1 < n and cabinets[i+1] == 'I' and placed[i+1]:
                covered = True  # 右边有电箱覆盖
            
            if not covered:  # 如果未被覆盖,尝试覆盖
                # 优先用右边间隔放电箱
                if i + 1 < n and cabinets[i+1] == 'I':
                    placed[i+1] = True  # 放电箱
                    count += 1
                # 右边不行,用左边间隔放电箱
                elif i - 1 >= 0 and cabinets[i-1] == 'I':
                    placed[i-1] = True  # 放电箱
                    count += 1
                else:  # 左右都不行,无解
                    return -1
    return count

# 输出部分:调用函数并打印
result = min_electric_boxes(cabinets)
print(result)

代码详解

  • 输入部分cabinets = input().strip() 直接读取输入字符串,简单高效。
  • 主体函数
    • 先检查是否有 'M',如果没有,直接返回 0(如输入 "I")。
    • placed 列表跟踪电箱位置,避免重复放置。
    • 核心循环:对每个 'M'
      • 先检查是否已被覆盖(左边或右边已有电箱)。
      • 未被覆盖时,优先放右边电箱(共享给后续),不行再放左边。
      • 如果都不能放,立即返回 -1
  • 输出部分:调用函数并打印结果,符合题目要求。

示例测试

用题目例子验证:

  • "MIIM":遍历时:
    • i=0 ('M'),未被覆盖,放右边 (i=1) 电箱,count=1。
    • i=3 ('M'),未被覆盖,放左边 (i=2) 电箱,count=2。输出 2。
  • "MIM"
    • i=0 ('M'),放右边 (i=1) 电箱,count=1。
    • i=2 ('M'),左边 (i=1) 已有电箱,覆盖。输出 1。
  • "M":i=0 ('M'),左右无 'I',返回 -1。
  • "MMM":i=0 ('M'),右边是 'M' 不是 'I',且左边无,返回 -1。
  • "I":无 'M',返回 0。

总结

这道题教会我们,贪心算法在覆盖类问题中非常实用:从左到右扫描,及时覆盖每个机柜,优先共享电箱。关键点:

  • 无效情况(如孤立机柜)要优先处理。
  • 用数组记录状态,避免重复放置。
  • 时间复杂度 O(n),空间复杂度 O(n),适合大数据。

作为初学者,多从简单例子入手,理解贪心策略的“局部最优导致全局最优”思想。希望这篇博客帮你掌握这道题!如果有疑问,欢迎留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值