Ask a question about the whole box of python.

the business is as follows:
there are warehouses A, B, C
there are several boxes of mineral water in each warehouse, and the quantity of mineral water in the boxes varies. How can the dissatisfied boxes be filled?
for example:
full of 24 bottles
A library has AME 1 = 21 bottles, A Mel 2 = 15 bottles, A Mel 3 = 13 bottles
B library has BMUI 1 = 4 bottles, BMET 2 = 8 bottles, BMET 3 = 23 bottles
C library has Cmurl 1 = 11
according to human logic, it should be moved between Amurl 1 and Almel 2. Then take three bottles out of Amur3 to Amur1 and nine bottles to AMUR 2, which is exactly two whole boxes of zero and 1
, and then put the remaining one bottle to Bmuri 3 to make a whole box
, and then half a case of Bmurl 1 and BMUE 2 to Cmurl 1 to make 23 bottles

.

the final requirement is to make a table to tell the storekeeper how many bottles from which box to put in which box. How should this business be realized?
tried the next cycle simulation, which is very resource-consuming. Is there a more efficient algorithm to solve this problem?

Feb.15,2022

in fact, there will be some conditions that are not very clear. I don't know how you calculate it.
the following is my idea. If you don't consider different warehouses, it is assumed that the circulation cost between any two boxes is the same.
take water from the least current box and put it into the most box to make the whole box. This ensures the minimum number of bottles to be moved.
if you consider different warehouses, as you said, you need to put each warehouse together first, so that there will be 0n irregular boxes left in N warehouses, and there will be no difference between them (or there may be a difference, because the distance between the warehouses is different, the distance between the boxes will not be considered in the same warehouse),

"""
    1.
    2.,
    3.NM[0~1]
"""
FULL = 24

def describe(frm, to, amount, cur):
    print("{}{}{},{}".format(frm, amount, to, cur))


def Do(_boxes):
    boxes = _boxes.copy()  -sharp 
    boxes.sort(key=lambda x: x["amount"], reverse=True)
    tail = len(boxes) - 1

    for index in range(len(boxes)):
        amount = boxes[index]["amount"]
        name = boxes[index]["name"]
        if amount == 0:
            -sharp ,,,
            break
        if index == tail:
            -sharp ,
            break
        while FULL - amount > 0 and index != tail:
            -sharp ,
            tail_amount = boxes[tail]["amount"]
            if tail_amount > (FULL-amount):
                -sharp ,,
                boxes[tail]["amount"] -= (FULL-amount)
                boxes[index]["amount"] = FULL
                describe(boxes[tail]["name"], name, FULL-amount, FULL)
                break
            else:
                -sharp ,,,
                boxes[index]["amount"] += tail_amount
                boxes[tail]["amount"] = 0
                describe(boxes[tail]["name"], name,
                         tail_amount, boxes[index]["amount"])
                tail -= 1
    return boxes


wh1 = [{"name": "a1",
        "amount": 21},
       {"name": "a2",
        "amount": 15},
       {"name": "a3",
        "amount": 13}]
wh2 = [{"name": "b1",
        "amount": 4},
       {"name": "b2",
        "amount": 8},
       {"name": "b3",
        "amount": 23}]
wh3 = [{"name": "c1",
        "amount": 11}]

wh1 = Do(wh1)
wh2 = Do(wh2)
wh3 = Do(wh3)
rest = []
for wh in (wh1, wh2, wh3):
    for i in wh:
        if i["amount"] < FULL and i["amount"] > 0:
            rest.append(i)
Do(rest)
//a33a1,24
//a39a2,24
//b11b3,24
//b13b2,11
//a31b2,12
//c111b2,23

later is a little different from what you described, because you are operating in sequence, bringing the unfinished A to B to become B4, mine is to deal with all before processing the rest, this algorithm is still relatively simple, but the efficiency is O (N), the space complexity is also O (N), I will take it as a problem

Menu