问题描述
小U准备了一些边长为整数的正方形巧克力板,希望选出若干块巧克力板,使它们的总面积恰好等于给定的整数n
。巧克力板的周长应尽可能小。巧克力板的总面积恰好为n
,而总周长为这些正方形边长的四倍和。请你帮助小U找到一个最优方案,输出最短的周长总和。
问题理解
经过简单分析我们需要找到若干个边长为整数的正方形巧克力板,使它们的总面积恰好等于给定的整数 n
,并且总周长最小。周长最小即意味着尽量使用边长较大的正方形。
数据结构选择
在这道题目中由于我们只需要计算周长,不需要存储具体的正方形边长,因此不需要复杂的数据结构。我们只需要一个变量来累加周长即可。
解题所用到的算法步骤
算法步骤
-
初始化周长总和:
- 使用一个变量
perimeter
来记录总周长,初始值为 0。
- 使用一个变量
-
贪心选择正方形:
- 使用贪心算法,每次选择最大的正方形边长
k
,使得k^2 <= n
。 - 计算当前正方形的周长并累加到
perimeter
中。 - 更新
n
为n - k^2
,表示剩余需要覆盖的面积。
- 使用贪心算法,每次选择最大的正方形边长
-
重复步骤:
- 重复上述步骤,直到
n
变为 0。
- 重复上述步骤,直到
详细步骤
-
找到最大的正方形边长:
- 计算
k = int(n ** 0.5)
,即k
是小于等于sqrt(n)
的最大整数。
- 计算
-
更新周长和剩余面积:
- 计算当前正方形的周长
4 * k
并累加到perimeter
中。 - 更新
n
为n - k^2
。
- 计算当前正方形的周长
-
循环直到
n
为 0:- 重复上述步骤,直到
n
变为 0。
- 重复上述步骤,直到
前置步骤完成代码详解
-
函数定义:
def solution(n: int) -> int:
定义了一个名为 solution
的函数,接受一个整数 n
作为参数,并返回一个整数。
-
初始化周长总和:
perimeter = 0
初始化一个变量 perimeter
,用于记录总周长,初始值为 0。
-
循环寻找正方形:
while n > 0:
使用 while
循环,当 n
大于 0 时,继续寻找正方形。
-
找到最大的正方形边长:
k = int(n ** 0.5)
计算 k = int(n ** 0.5)
,即 k
是小于等于 sqrt(n)
的最大整数。这个 k
就是当前最大的正方形边长。
-
更新剩余面积:
n -= k * k
更新 n
为 n - k^2
,表示剩余需要覆盖的面积。
-
累加周长:
perimeter += 4 * k
计算当前正方形的周长 4 * k
并累加到 perimeter
中。
-
返回结果:
return perimeter
当 n
变为 0 时,循环结束,返回总周长 perimeter
。
总结
这道题通过寻找若干个正方形巧克力板,使它们的总面积恰好等于给定的整数 n
,并且总周长最小,展示了贪心算法的核心思想。通过每次选择最大的正方形边长,可以逐步减少剩余面积,从而确保总周长最小。这个过程不仅帮助我理解了贪心算法的应用场景,还让我掌握了如何通过简单的数学运算(如平方根)来优化问题的解决方案。此外,通过实现和调试代码,我学会了如何在循环中动态更新变量,并逐步逼近问题的最优解。这道题不仅提升了我的编程技能,还加深了对算法设计和优化的理解,为解决类似的最优化问题提供了宝贵的经验。
完整代码
def solution(n: int) -> int:
# 初始化周长总和
perimeter = 0
# 当 n 大于 0 时,继续寻找正方形
while n > 0:
# 找到最大的正方形边长 k,使得 k^2 <= n
k = int(n ** 0.5)
# 更新 n 为 n - k^2
n -= k * k
# 累加周长
perimeter += 4 * k
return perimeter
if __name__ == '__main__':
print(solution(n=11) == 20)
print(solution(n=13) == 20)
print(solution(n=25) == 20)