题目描述:
小U准备了一些边长为整数的正方形巧克力板,目标是从中选择若干块巧克力板,使它们的总面积恰好等于给定的整数 ( n ),并且要求选择的巧克力板的总周长尽可能小。每块正方形巧克力板的周长是其边长的四倍,而面积是其边长的平方。
任务:
- 给定整数 ( n ),你需要选出若干块正方形巧克力板,确保它们的总面积等于 ( n ),并且它们的总周长最小。
- 输出这个最小的周长。
输入格式:
- 一个整数 ( n ) (( 1 <= n <= 10^5 ))。
输出格式:
- 一个整数,表示最小的周长。
解答
这个问题可以通过动态规划和贪心的策略来解决,目标是找到若干个边长为整数的正方形巧克力板,使它们的总面积恰好等于给定的整数 ( n ),并且总周长尽可能小。具体的解决步骤如下:
问题分析
- 正方形的面积与周长:
- 如果一个正方形的边长为 ( a ),那么它的面积是 ( a^2 ),周长是 ( 4a )。
- 目标:我们需要选择若干块正方形巧克力板,使它们的总面积恰好等于 ( 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 ) 上后的周长。
实现步骤:
- 初始化
dp数组,其中dp[0] = 0,其它元素初始化为一个较大的值(比如无限大)。 - 遍历所有的面积 ( i ) 和正方形边长 ( a ),按照动态规划的转移方程更新
dp数组。 - 最终,
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
代码说明:
- 初始化:
dp[0] = 0,表示面积为 0 时周长为 0,其它dp[i]初始化为无穷大,表示尚未计算出最小周长。 - 动态规划更新:对于每个面积 ( i )(从 1 到 ( n )),我们遍历所有可能的正方形边长 ( a ),更新
dp[i]为当前面积 ( i ) 的最小周长。 - 最终结果:
dp[n]存储了面积为 ( n ) 时的最小周长。
复杂度分析:
- 时间复杂度:由于每个面积 ( i ) 需要遍历所有边长 ( a )(最多为 ( \sqrt{n} ) 个边长),因此时间复杂度为 ( O(n \cdot \sqrt{n}) )。
- 空间复杂度:我们使用一个大小为 ( n+1 ) 的数组
dp,因此空间复杂度为 ( O(n) )。