青训营X豆包MarsCode 技术训练营刷题5 | 豆包MarsCode AI 刷题

36 阅读3分钟

题目描述:
小U准备了一些边长为整数的正方形巧克力板,目标是从中选择若干块巧克力板,使它们的总面积恰好等于给定的整数 ( n ),并且要求选择的巧克力板的总周长尽可能小。每块正方形巧克力板的周长是其边长的四倍,而面积是其边长的平方。

任务:

  • 给定整数 ( n ),你需要选出若干块正方形巧克力板,确保它们的总面积等于 ( n ),并且它们的总周长最小。
  • 输出这个最小的周长。

输入格式:

  • 一个整数 ( n ) (( 1 <= n <= 10^5 ))。

输出格式:

  • 一个整数,表示最小的周长。

解答

这个问题可以通过动态规划和贪心的策略来解决,目标是找到若干个边长为整数的正方形巧克力板,使它们的总面积恰好等于给定的整数 ( n ),并且总周长尽可能小。具体的解决步骤如下:

问题分析

  1. 正方形的面积与周长
    • 如果一个正方形的边长为 ( a ),那么它的面积是 ( a^2 ),周长是 ( 4a )。
  2. 目标:我们需要选择若干块正方形巧克力板,使它们的总面积恰好等于 ( n ),并且总周长最小。

解题策略

我们可以使用动态规划来解决这个问题:

  • 定义 dp[i] 为面积为 ( i ) 时的最小周长。
  • 初始化 dp[0] = 0(如果面积为 0,没有巧克力板,总周长为 0)。
  • 对于每一个正方形的边长 ( a ),它的面积为 ( a^2 ),可以用这个正方形来构成更大的面积 ( i )(即 ( dp[i] )),并更新相应的周长。

动态规划的转移方程:

  • 对于每个 ( i )(从 1 到 ( n )),遍历所有可能的边长 ( a )(从 1 到 ( \sqrt{n} )),如果 ( i \geq a^2 ),则: [ dp[i] = \min(dp[i], dp[i - a^2] + 4a) ] 其中,dp[i - a^2] + 4a 代表我们将一个边长为 ( a ) 的正方形加到已有面积 ( i - a^2 ) 上后的周长。

实现步骤:

  1. 初始化 dp 数组,其中 dp[0] = 0,其它元素初始化为一个较大的值(比如无限大)。
  2. 遍历所有的面积 ( i ) 和正方形边长 ( a ),按照动态规划的转移方程更新 dp 数组。
  3. 最终,dp[n] 就是总面积为 ( n ) 时的最小周长。

代码实现:

import math

def minPerimeter(n):
    # dp[i] 存储面积为 i 时的最小周长
    dp = [float('inf')] * (n + 1)
    dp[0] = 0  # 面积为 0 时周长为 0

    # 遍历所有面积从 1 到 n
    for i in range(1, n + 1):
        # 遍历所有边长 a,使得 a^2 <= i
        for a in range(1, int(math.sqrt(i)) + 1):
            area = a * a
            if i >= area:
                dp[i] = min(dp[i], dp[i - area] + 4 * a)
    
    return dp[n]

# 测试样例
print(minPerimeter(11))  # 输出 20
print(minPerimeter(13))  # 输出 20
print(minPerimeter(25))  # 输出 20

代码说明:

  1. 初始化dp[0] = 0,表示面积为 0 时周长为 0,其它 dp[i] 初始化为无穷大,表示尚未计算出最小周长。
  2. 动态规划更新:对于每个面积 ( i )(从 1 到 ( n )),我们遍历所有可能的正方形边长 ( a ),更新 dp[i] 为当前面积 ( i ) 的最小周长。
  3. 最终结果dp[n] 存储了面积为 ( n ) 时的最小周长。

复杂度分析:

  • 时间复杂度:由于每个面积 ( i ) 需要遍历所有边长 ( a )(最多为 ( \sqrt{n} ) 个边长),因此时间复杂度为 ( O(n \cdot \sqrt{n}) )。
  • 空间复杂度:我们使用一个大小为 ( n+1 ) 的数组 dp,因此空间复杂度为 ( O(n) )。