并且使用函数应返回数字总和的表达式从 blist 以列表的形式加起来为 'a'。如果不存在总和,则返回一个空列表[ ]。
def sum_ex( a, i=0 blist)#用来验证True 和False
def find_s(a, i = 0, blist, slist)
#用来验证加法的过程,例如a = 17 且 blist = [2, 3, 5]如果存在总和,return[2,2,2,2,2,2,2,3] 或是a=9 blist= [5, 6] 不存在总和,会 return [ ]
结题思路:
递归求和 n = int(input()) jie = 1 sum = 0 i = 1 while n >= i: jie = jie * i sum = sum + jie i = i + 1 print(sum)
当所有 list[i]都小于等于 list[i+1]才返回true,只要有一个 list[i]大于 list[i+1]就返回false.
from random import randint
def sum_exist(n,p_list, i=0):
if n<min(p_list) or i>=len(p_list):
return False
else:
for p in p_list:
if n%p==0:
return True
else:
return sum_exist(n-p_list[i],p_list,i) or sum_exist(n,p_list,i+1)
def find_s(n, p_list, sum_list, i=0):
if n<min(p_list) or i>=len(p_list):
return []
else:
for p in p_list:
if n%p==0:
for _ in range(n//p):
sum_list.append(p)
return sum_list
else:
result = find_s(n-p_list[i], p_list, sum_list+[p_list[i]])
if len(result)>0:
return result
else:
return find_s(n, p_list, sum_list, i+1)
# ns = [17,7,107,43,146]
# p_lists = [[2,3,5],[3,5],[2,3,37],[3,29],[17,29,37]]
ns = []
p_lists = []
PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]
for i in range(10):
num = randint(1,4)
p_list = [PRIMES[randint(0,len(PRIMES)-1)] for _ in range(num)]
p_list = list(set(p_list))
p_list.sort()
p_lists.append(p_list)
ns.append(randint(2,100))
print("="*200)
print(f'{"n":<5}{"P_list":<20}{"Expected Result":<10}')
for n,p_list in zip(ns,p_lists):
result = sum_exist(n, p_list)
print(f'{str(n):<5}{str(p_list):<20}{str(result):<10}')
print("="*200)
print(f'{"n":<5}{"P_list":<20}{"Expected Result":<120}{"check":<10}{"sum_exist":<10}')
for n,p_list in zip(ns,p_lists):
result = find_s(n, p_list, [])
print(f'{str(n):<5}{str(p_list):<20}{str(result):<120}{str(sum(result)==n):<10}{str(sum_exist(n, p_list)):<10}')
楼上的改一下
def sum_ex(a,blist,lst=[],lst1=[]):
if a==0:
lst1.append(lst)
elif a<0:
pass
else:
for b in blist:
lst_copy = lst.copy()
lst_copy.append(b)
cur = a-b
sum_ex(cur,blist,lst_copy,lst1)
if len(lst1)>0:
return True
else:
return False
def find_s(a,blist,lst=[],lst1=[]):
if a==0:
lst1.append(lst)
elif a<0:
pass
else:
for b in blist:
lst_copy = lst.copy()
lst_copy.append(b)
cur = a-b
find_s(cur,blist,lst_copy,lst1)
if len(lst1)>0:
return lst1[0]
else:
return []
其实思路并不复杂,就是一方面向下依次尝试用 n 减去列表 b_list 中索引为 i 的元素,直到 n 小于等于索引为 i 的元素,另一方面横向递增 i,尝试使用列表中不同的元素。如果尝试的过程中找到解,则停止搜索,立即返回,不然就一直到所有元素都试过。
题目给的函数的形参,也暗示了剪枝条件:n 和 i。
纵向剪枝:n < b_list[i],表示已经无法再继续减下去
横向剪枝:i >= len(b_list),表示在这一层已经尝试过列表中所有元素
有解的情况必然是当前剩下的数等于列表中某个元素,也就是 n = b_list[i],但是纵向 n 递减,横向 i 递增,所以需要两个方向的递归。
代码实现如下:
def sum_ex(n, b_list, i=0):
if i>=len(b_list) or n < b_list[i]: return False
if n == b_list[i]: return True
return sum_ex(n-b_list[i], b_list) or sum_ex(n, b_list, i+1)
def find_s(n, b_list, sum_list, i=0):
if i>=len(b_list) or n < b_list[i]: return []
if n == b_list[i]: return sum_list+[b_list[i]]
res = find_s(n-b_list[i], b_list, sum_list+[b_list[i]])
return res if res else find_s(n, b_list, sum_list, i+1)
a = 17
b_list = [2,3,5]
print(sum_ex(a,b_list))
res = find_s(a,b_list, list())
if res:
print(f"{'+'.join(map(str,sorted(find_s(a,b_list, list()))))}={a}")
else:
print(res)
注意:因为是只要找到某个解就返回,所以代码的返回其实是最小的列表。
比如题目中的例子,下面两个答案都可以得到17,但是代码返回的是上面这个最小的列表。
[2,2,2,2,2,2,2,3]
[2,5,5,5]
牛顿迭代法写的递归可以嘛