编账的尽头是数学

反正文章的题目,总是要取牛一点。下面献上适用程序,多元一次方程,求正整数解。要求得数都是正整数。适合的情况最好是元素的数值离总和远一点,太近也没啥意思。因为接近暴力枚举,最好还是不要太多元吧。个人试了下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: 其实可以其他不改,但再包一层多线程,这样算的更快。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

取啥都被占用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值