反正文章的题目,总是要取牛一点。下面献上适用程序,多元一次方程,求正整数解。要求得数都是正整数。适合的情况最好是元素的数值离总和远一点,太近也没啥意思。因为接近暴力枚举,最好还是不要太多元吧。个人试了下5元还能凑合,再上去有点想哭。
经验之谈,随机数比遍历算的快,如果一次跑太久,大可以断了重新跑一下,可能就一会儿就出来了。说白了是个工程类的东西,讲究能用,逻辑是不够严谨的。
欢迎取用,歪打正着!
如果有更好的逻辑,请评论给意见。经过实践,3元及以上用了random反而速度体验上更好,算的快些。遍历每次都是重头来,无尽的等待。
import numpy as np
import random
def has_result(list_of_cost,total_amount):
arr = np.array(list_of_cost)
int_gcd = np.gcd.reduce(arr)
return (total_amount % int_gcd == 0)
def volume_calc(list_of_cost,total_amount):
number_of_parts = len(list_of_cost)
list_of_cost.sort(reverse=True) #升序排序,大的成本在前。
item_max_range = []
item_parity_range = []
for i in list_of_cost:
item_max_range.append(total_amount // i + 1) #每个成分货品的顶格数量。
for i in list_of_cost:
item_parity_range.append(total_amount // i // number_of_parts + 1) #差不多1/n的金额数量的位置。
flag = 0
item_volume_max = 0
item_volume_min = item_parity_range[0]
item_middle_range = item_parity_range.copy() 可一定得用copy,不然是传递性的。
while flag == 0:
print("stupid loop!")
krr = []
for item in list_of_cost:
item_number = list_of_cost.index(item)
if item == max(list_of_cost):
krr.append(item * item_volume_min)
elif item != min(list_of_cost):
krr.append(item * item_middle_range[item_number])
continue
else:
while total_amount > (sum(krr) + item * item_volume_max):
item_volume_max = item_volume_max + 1
if sum(krr) + item * item_volume_max == total_amount:
flag = 1
if number_of_parts == 3:
print(item_volume_min, item_middle_range[1],item_volume_max)
else:
print(item_volume_min, item_middle_range[1:-1],item_volume_max)
break
else:
if item_volume_min -1 > 0:
item_volume_min = item_volume_min - 1
else:
item_volume_min = item_max_range[0]
if number_of_parts == 3:
item_middle_range[1] = item_middle_range[1] - random.randrange(9) #这边会给盯着死减
if item_middle_range[1] < 0:
item_middle_range[1] = item_parity_range[1]
break
elif number_of_parts > 3:
list_items = range(number_of_parts)
random_item = random.choice(list_items[1:-1]) # max与min不会被选到调整最大值
item_middle_range[random_item] = item_middle_range[random_item] - random.randrange(9)
if item_middle_range[random_item] < 0:
item_middle_range[random_item] = item_parity_range[random_item]
break
else:
print("new round...", item_volume_min,item_volume_max)
item_volume_max = 0
break
return 0
def minor_mod_price(list_of_cost): #minor mod cost
list_of_random = [1,2,3,5,7] # all prime numbers
arr = np.array(list_of_cost)
n_arr = len(arr)
while np.gcd.reduce(arr) !=1:
item_num = random.randrange(n_arr)
arr[item_num] = arr[item_num] + random.choice(list_of_random)
print("calculating with changed No.%d, and changing to %f ",item_num,arr[item_num])
return arr
if __name__ == "__main__":
#此处有个中心思想,成本的数字远小于总的金额数,才导致了需要程序凑,不然的话,人脑就可以凑出来。
list_costs = [311,153,146,56] #最好按从大到小给,因为后续也会这么sort。
total_amt = 28000
if has_result(list_costs,total_amt):
volume_calc(list_costs,total_amt)
else:
print("the combination cannot get proper integer volume for use!")
#print(minor_mod_price(list_costs)) # 如果成本金额的数字允许微调,可以考虑用这个函数馊主意。
我想过用sympy,看着里面的Diophantine是个好东西,但问题是,要用这个,估计数学水平还得高一些。我抽象的理解的不好,基础也不好,只能用线性思维搞定它。
2023-05-01: 其实可以其他不改,但再包一层多线程,这样算的更快。