The end of accounting is mathematics

Anyway, the title of the article should always be a little more interesting. The following is a suitable program for finding positive integer solutions to linear equations of multiple variables. The required numbers are all positive integers. The best situation is when the value of the element is far away from the sum. It is meaningless if it is too close. Since it's close to a brute force enumeration, it's best not to have too many variables. Personally, I tried it for 5 yuan and it was okay, but I felt like crying when I went up.

Speaking from experience, random numbers are calculated faster than traversal. If one run takes too long, you can stop and run again, and it may come out in a while. To put it bluntly, it is an engineering thing, and it is about usability, but the logic is not rigorous enough.

Welcome to use it, it’s a good idea!

If there is a better logic, please comment to give feedback. After practice, if you use random for 3 yuan or more, the speed experience is better and the calculation is faster. Every time I go through it, I have to start over again, waiting endlessly.

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))   # 如果成本金额的数字允许微调,可以考虑用这个函数馊主意。

I thought about using sympy, and the Diophantine in it was a good thing, but the problem is that to use this, I guess my math level needs to be higher. My abstract understanding is not good, and my foundation is not good, so I can only use linear thinking to solve it.

2023-05-01: In fact, you can keep the rest unchanged, but add a layer of multi-threading to make the calculation faster.

Guess you like

Origin blog.csdn.net/u011410413/article/details/130212614