蓝桥杯备战日志(Python)3-货物摆放(枚举、因子分解)
原创
©著作权归作者所有:来自51CTO博客作者Helloyouth的原创作品,请联系作者获取转载授权,否则将追究法律责任
原题
暴力枚举因子
首先明确“因子”的概念:对一个正整数n,若正整数i能够整除n,则i称为n的一个因子。很容易得知,因子是“对称的”,即对于n的因子i,有n//i (n整除i)的结果也是n的因子,所以给定一个正整数n,可以在√n的时间复杂度内使用“试除法”求出n的所有因子,代码如下:
# 暴力枚举,运行时间12秒左右
n=2021041820210418
# 存放因子的列表
factor_l = [1,n]
# 求n的因子的时间复杂度为n**0.5(根号n)
t = int(n ** 0.5) + 1
for i in range(2,t):
d,m = divmod(n,i)
if m == 0:
factor_l.append(i)
factor_l.append(d)
# 枚举满足条件的L,W,H
res_s = set() # 使用集合筛掉一些重复的情况
for L in factor_l:
for W in factor_l:
temp = L*W
H,m = divmod(n,temp)
if m == 0:
res_s.add( (L,W,H) )
print(len(res_s))
蓝桥杯比赛中能做出以上的暴力枚举即可,时间复杂度不算很高,是能够拿下的!
枚举优化——质因数分解
本题可以使用数学方法对枚举进行优化,在此之前需要回顾一下质数和合数的一些概念:
- 在所有正整数中(1,2,3,4,5,6,7,8,...)
- 1既不是质数也不是合数
- 质数:只能被1和它本身整除的数
- 合数:除质数和1外的所有自然数
- 一个合数等于有限个质数的乘积 (更严格的说,应该是如下基本定理的推论:任何一个大于1的正整数都能分解为有限个质数的幂的乘积)
一个正整数n(n>1),若它本身不是质数,则其可以被分解为有限个质数(质因数)相乘。求出n的质因数后,可通过其质因数快速地求出n的所有因子,所以这里相对于上述暴力枚举的优化在于,更快地求出n的所有因子,n越大算法效率提升的效果越明显。
这里再作进一步说明为什么通过质因数求n的所有因子效率会更高。首先,在纯暴力枚举中,求n得所有因子需要遍历√n范围内的每个整数作除法求余数,而通过先求质因数(尽管n很大,其质因数的数量也很少)再求其所有因子的方法,将程序作除法的操作大大缩减(计算机中作乘法比作除法的效率更高)。
- 从i=2开始枚举,若 n % i != 0,则i += 1继续往下枚举
- 当 n % i == 0 成立时,n中已经不包含任何2 ~ (i - 1)的质因子,又因为此时n是i的倍数,所以i中也不包含2 ~ (i - 1)的因子,所以此时i一定是质数
- 这里的一个关键是当 n % i == 0时,n的取值应更新为n//i
- 因为我们最终求得的质因数列表的所有元素的乘积为最初的n
- 如求得100的质因数列表为[2,2,5,5],有2*2*5*5=100
- 初始化当前n的因子的集合(只有元素1)
- 遍历求得的质因数列表,令每个元素(质因数)与当前已求得的因子作乘法,乘积结果加入存放因子的集合。
参考:https://www.acwing.com/blog/content/30069/
# 对整数x进行质因数分解
def find_prime_factor(n: int):
prime_factor_l = []
i = 2
while i*i <= n:
d,m = divmod(n,i)
# i的起始值为2(质数),若当前x能被i整除,i添加至列表,并将x的值变为x//i,即d
# 这里反复利用了那个定理:一个合数能被分解成有限个质数相乘
if m == 0:
prime_factor_l.append(i)
n = d
else:
# 若i当前为2则下一个值为i+1, 否则为i+2,以更快地找到下一个质数
i = i+1 if i==2 else i+2
prime_factor_l.append(n)
return prime_factor_l
n = 2021041820210418
prime_factor_l = find_prime_factor(n)
s=set() # 用于存因子 如10=1*2*5*10
s.add(1)
# 通过质因数求出所有因子
for j in prime_factor_l:
p=set()
for k in s:
p.add(j*k)
for k in p:
s.add(k)
count = 0
for L in s: # 遍历两层求解
for W in s:
if n%(L*W)==0:
count += 1
print(count)
上一篇:蓝桥杯备战日志(Python)2-相乘(逆向枚举)