最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Confused on a simple SAT problem using Python z3 - Stack Overflow

programmeradmin2浏览0评论

Problem Statement

Five trucks, including two fridge trucks, have to deliver the following 131 items to a grocery in Brisbane using no more than twenty pallets.

  • 21 bunches of bananas, 2kg per bunch
  • 20 bunches of tomatoes, 1.8kg per bunch
  • 25 bags of nuts, 1.2kg per bag
  • 30 bags of candies, 1kg per bag
  • 35 packs of milk, 0.2kg per pack

Any solution to the problem should satisfy all of the following constraints.

  • Each pallet can carry no more than 8 items, with a weight limit of 10kg.
  • Candies and nuts can often mix, so they should not be carried on the same pallet.
  • Each truck can carry no more than 30 items, with a weight limit of 40kg.
  • Milk must be cooled, so it should be carried by a fridge truck.
  • Bananas are valuable, so each truck can carry no more than 5 bunches of bananas.

I am finding it difficult to find a satisfiable solver for the problem.

Confused about if I should map each item to the objects or if i should just focus on the pallets and trucks. Total beginner to z3 and satisfiability problems.

from z3 import *

total_quantity = 131
max_trucks = 5
max_pallets = 20

items = {
    "bananas": (21, 2),
    "tomatoes": (20, 1.8),
    "nuts": (25, 1.2),
    "candies": (30, 1),
    "milk": (35, 0.2)
}

p = Function('p', IntSort(), IntSort(), BoolSort()) #confirms if item is in pallet
fridge = Function('fridge', IntSort(), BoolSort()) #confirms if its a fridge truck

s = Solver()

# Set Fridge Trucks
constraint_data = [fridge(i) for i in range(max_trucks)]
s.add(Sum(constraint_data) == 2)

# Set Maximum number of pallets as 20
constraint_data = Or([p(item,pallet) for item in range(total_quantity) for pallet in range(max_pallets)])
s.add(Sum(constraint_data) <= max_pallets)

# Constraint1 - Set Pallet Capacity
for pallet in range(max_pallets):
    quantity_constraint_data = [p(item, pallet) for item in range(total_quantity)]
    weight_constraint_data = []

Problem Statement

Five trucks, including two fridge trucks, have to deliver the following 131 items to a grocery in Brisbane using no more than twenty pallets.

  • 21 bunches of bananas, 2kg per bunch
  • 20 bunches of tomatoes, 1.8kg per bunch
  • 25 bags of nuts, 1.2kg per bag
  • 30 bags of candies, 1kg per bag
  • 35 packs of milk, 0.2kg per pack

Any solution to the problem should satisfy all of the following constraints.

  • Each pallet can carry no more than 8 items, with a weight limit of 10kg.
  • Candies and nuts can often mix, so they should not be carried on the same pallet.
  • Each truck can carry no more than 30 items, with a weight limit of 40kg.
  • Milk must be cooled, so it should be carried by a fridge truck.
  • Bananas are valuable, so each truck can carry no more than 5 bunches of bananas.

I am finding it difficult to find a satisfiable solver for the problem.

Confused about if I should map each item to the objects or if i should just focus on the pallets and trucks. Total beginner to z3 and satisfiability problems.

from z3 import *

total_quantity = 131
max_trucks = 5
max_pallets = 20

items = {
    "bananas": (21, 2),
    "tomatoes": (20, 1.8),
    "nuts": (25, 1.2),
    "candies": (30, 1),
    "milk": (35, 0.2)
}

p = Function('p', IntSort(), IntSort(), BoolSort()) #confirms if item is in pallet
fridge = Function('fridge', IntSort(), BoolSort()) #confirms if its a fridge truck

s = Solver()

# Set Fridge Trucks
constraint_data = [fridge(i) for i in range(max_trucks)]
s.add(Sum(constraint_data) == 2)

# Set Maximum number of pallets as 20
constraint_data = Or([p(item,pallet) for item in range(total_quantity) for pallet in range(max_pallets)])
s.add(Sum(constraint_data) <= max_pallets)

# Constraint1 - Set Pallet Capacity
for pallet in range(max_pallets):
    quantity_constraint_data = [p(item, pallet) for item in range(total_quantity)]
    weight_constraint_data = []

Share Improve this question asked Mar 18 at 13:44 Kiran CJKiran CJ 612 silver badges6 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 2

I recently learnt about Clingo ASP, and enjoy its concise and ‘elegant’ way to model such combinatorial problems.

So, here is my attempt:
It’s not as fast as Axels minizinc model w/ CP-SAT ...

(see below update for a faster model)

% --- Global Constraints ---
%%% #const total_quantity = 131.
#const max_trucks = 5.
#const max_pallets = 20.
#const fridge_trucks = 2.
#const max_items_per_pallet = 8.
#const max_weight_per_pallet = 10000.  % 10kg
#const max_items_per_truck = 30.
#const max_weight_per_truck = 40000.   % 40kg
#const max_bananas_per_truck = 5.

%%%%% Facts --------------------------------

item("bananas", 1..21, 2000).  % 2kg each
item("tomatoes", 1..20, 1800). % 1.8kg each
item("nuts", 1..25, 1200).     % 1.2kg each
item("candies", 1..30, 1000).  % 1kg each
item("milk", 1..35, 200).      % 0.2kg each

pallet(1..max_pallets).
truck(1..max_trucks).

%%%%% Rules --------------------------------

{ item_pallet(I, Q, P) : pallet(P) } = 1 :- item(I, Q, _).
{ pallet_truck(P, T) : truck(T) } = 1 :- item_pallet(_, _, P).
truck_pallet_item(T, P, I, Q) :- item_pallet(I, Q, P), pallet_truck(P, T).

%%%%% Constraints ---------------------------

% --- Ensure pallets' max items and max weight ---
:- pallet(P), #sum { 1, I, Q: item_pallet(I, Q, P) } > max_items_per_pallet.
:- pallet(P), #sum { Wt, I, Q: item_pallet(I, Q, P), item(I, Q, Wt) } > max_weight_per_pallet.

% --- Candies and nuts must not be on the same pallet ---
:- item_pallet("candies", _, P), item_pallet("nuts", _, P).

% --- Milk must go on a fridge truck ---
:- pallet_truck(P, T), item_pallet("milk", _, P), T > fridge_trucks.

% --- Symmetry breaking ---
:- truck_pallet_item(T, P1, I, Q1), truck_pallet_item(T, P2, I, Q2), P1 > P2, Q1 < Q2.

% --- Ensure trucks' max items and max weight ---
:- truck(T), #sum { 1, I, Q, P : item_pallet(I, Q, P), pallet_truck(P, T) } > max_items_per_truck.
:- truck(T), #sum { Wt, I, Q, P : item_pallet(I, Q, P), item(I, Q, Wt), pallet_truck(P, T) } > max_weight_per_truck.

% --- No truck can carry more than max bunches of bananas ---
:- truck(T), #sum { 1, Q : item_pallet("bananas", Q, P), pallet_truck(P, T) } > max_bananas_per_truck.

% Output ----------------------------
#show truck_pallet_item/4.

Output: (copy and paste the code to run it online)

clingo version 5.7.2 (6bd7584d)
Reading from stdin
Solving...
Answer: 1
truck_pallet_item(2,1,"bananas",5) truck_pallet_item(2,1,"tomatoes",7) truck_pallet_item(2,1,"candies",2) truck_pallet_item(2,1,"milk",1) truck_pallet_item(2,1,"milk",2) truck_pallet_item(2,1,"milk",3) truck_pallet_item(3,2,"bananas",13) truck_pallet_item(3,2,"bananas",15) truck_pallet_item(3,2,"bananas",19) truck_pallet_item(3,2,"nuts",6) truck_pallet_item(3,2,"nuts",9) truck_pallet_item(3,2,"nuts",19) truck_pallet_item(4,3,"tomatoes",9) truck_pallet_item(4,3,"candies",5) truck_pallet_item(4,3,"candies",12) truck_pallet_item(4,3,"candies",16) truck_pallet_item(4,3,"candies",18) truck_pallet_item(4,3,"candies",19) truck_pallet_item(4,3,"candies",20) truck_pallet_item(4,3,"candies",21) truck_pallet_item(5,4,"bananas",2) truck_pallet_item(5,4,"bananas",12) truck_pallet_item(5,4,"bananas",14) truck_pallet_item(5,4,"bananas",16) truck_pallet_item(5,4,"candies",7) truck_pallet_item(5,4,"candies",10) truck_pallet_item(4,5,"bananas",6) truck_pallet_item(4,5,"bananas",7) truck_pallet_item(4,5,"bananas",8) truck_pallet_item(4,5,"bananas",10) truck_pallet_item(4,5,"nuts",12) truck_pallet_item(2,6,"candies",9) truck_pallet_item(2,6,"candies",24) truck_pallet_item(2,6,"candies",26) truck_pallet_item(2,6,"milk",8) truck_pallet_item(2,6,"milk",9) truck_pallet_item(2,6,"milk",10) truck_pallet_item(2,6,"milk",12) truck_pallet_item(2,6,"milk",16) truck_pallet_item(5,7,"bananas",18) truck_pallet_item(5,7,"nuts",1) truck_pallet_item(5,7,"nuts",2) truck_pallet_item(5,7,"nuts",3) truck_pallet_item(5,7,"nuts",7) truck_pallet_item(5,7,"nuts",10) truck_pallet_item(5,7,"nuts",11) truck_pallet_item(5,8,"tomatoes",3) truck_pallet_item(5,8,"nuts",13) truck_pallet_item(5,8,"nuts",14) truck_pallet_item(5,8,"nuts",15) truck_pallet_item(5,8,"nuts",16) truck_pallet_item(5,8,"nuts",17) truck_pallet_item(5,8,"nuts",18) truck_pallet_item(4,9,"bananas",17) truck_pallet_item(4,9,"tomatoes",16) truck_pallet_item(4,9,"candies",22) truck_pallet_item(4,9,"candies",25) truck_pallet_item(4,9,"candies",28) truck_pallet_item(4,9,"candies",29) truck_pallet_item(4,9,"candies",30) truck_pallet_item(5,10,"tomatoes",6) truck_pallet_item(5,10,"tomatoes",8) truck_pallet_item(5,10,"tomatoes",15) truck_pallet_item(5,10,"nuts",23) truck_pallet_item(5,10,"nuts",24) truck_pallet_item(5,10,"nuts",25) truck_pallet_item(2,11,"bananas",11) truck_pallet_item(2,11,"nuts",4) truck_pallet_item(2,11,"nuts",5) truck_pallet_item(2,11,"nuts",8) truck_pallet_item(2,11,"milk",17) truck_pallet_item(2,11,"milk",18) truck_pallet_item(2,11,"milk",19) truck_pallet_item(2,11,"milk",20) truck_pallet_item(1,12,"bananas",1) truck_pallet_item(1,12,"bananas",3) truck_pallet_item(1,12,"bananas",4) truck_pallet_item(1,12,"bananas",9) truck_pallet_item(1,12,"nuts",21) truck_pallet_item(1,13,"tomatoes",4) truck_pallet_item(1,13,"candies",11) truck_pallet_item(1,13,"candies",13) truck_pallet_item(1,13,"milk",4) truck_pallet_item(1,14,"milk",5) truck_pallet_item(1,14,"milk",6) truck_pallet_item(1,14,"milk",7) truck_pallet_item(1,14,"milk",11) truck_pallet_item(1,14,"milk",13) truck_pallet_item(1,14,"milk",14) truck_pallet_item(1,14,"milk",15) truck_pallet_item(1,14,"milk",21) truck_pallet_item(1,15,"bananas",21) truck_pallet_item(1,15,"milk",22) truck_pallet_item(1,15,"milk",24) truck_pallet_item(1,15,"milk",25) truck_pallet_item(1,15,"milk",26) truck_pallet_item(3,16,"bananas",20) truck_pallet_item(3,16,"tomatoes",1) truck_pallet_item(3,16,"tomatoes",2) truck_pallet_item(3,16,"candies",1) truck_pallet_item(3,16,"candies",3) truck_pallet_item(3,17,"tomatoes",5) truck_pallet_item(3,17,"tomatoes",10) truck_pallet_item(3,17,"tomatoes",11) truck_pallet_item(3,17,"tomatoes",12) truck_pallet_item(3,17,"candies",4) truck_pallet_item(3,17,"candies",6) truck_pallet_item(1,18,"milk",27) truck_pallet_item(1,18,"milk",28) truck_pallet_item(1,18,"milk",29) truck_pallet_item(1,18,"milk",30) truck_pallet_item(1,18,"milk",31) truck_pallet_item(1,18,"milk",32) truck_pallet_item(1,18,"milk",33) truck_pallet_item(1,18,"milk",34) truck_pallet_item(3,19,"tomatoes",18) truck_pallet_item(3,19,"tomatoes",20) truck_pallet_item(3,19,"candies",8) truck_pallet_item(3,19,"candies",14) truck_pallet_item(3,19,"candies",15) truck_pallet_item(3,19,"candies",17) truck_pallet_item(3,19,"candies",23) truck_pallet_item(3,19,"candies",27) truck_pallet_item(2,20,"tomatoes",13) truck_pallet_item(2,20,"tomatoes",14) truck_pallet_item(2,20,"tomatoes",17) truck_pallet_item(2,20,"tomatoes",19) truck_pallet_item(2,20,"nuts",20) truck_pallet_item(2,20,"nuts",22) truck_pallet_item(2,20,"milk",23) truck_pallet_item(2,20,"milk",35)
SATISFIABLE

Models       : 1+
Calls        : 1
Time         : 11.958s (Solving: 5.38s 1st Model: 5.38s Unsat: 0.00s)
CPU Time     : 0.000s

And this second part takes the result from above to verify the assigned items and the total load on all trucks:

% --- Global Constraints ---
#const total_quantity = 131.
#const total_weight = 145000.
#const max_trucks = 5.
#const max_pallets = 20.
#const fridge_trucks = 2.
#const max_items_per_pallet = 8.
#const max_weight_per_pallet = 10000.  % 10kg
#const max_items_per_truck = 30.
#const max_weight_per_truck = 40000.   % 40kg
#const max_bananas_per_truck = 5.

%%%%% Facts ---------------------------------

item("bananas", 1..21, 2000).  % 2kg each
item("tomatoes", 1..20, 1800). % 1.8kg each
item("nuts", 1..25, 1200).     % 1.2kg each
item("candies", 1..30, 1000).  % 1kg each
item("milk", 1..35, 200).      % 0.2kg each

truck(1..max_trucks).

% --- Input truck_pallet_item from previous step ---
% Example input (paste actual output from Step 1):
% truck_pallet_item(1, 3, "bananas", 2). = truck 1, pallet 3, bananas, batch #3
% truck_pallet_item(1, 3, "tomatoes", 5).
% ...

truck_pallet_item(1,12,"bananas",1). truck_pallet_item(1,12,"bananas",3). truck_pallet_item(1,12,"bananas",4). truck_pallet_item(1,12,"bananas",9). truck_pallet_item(1,12,"nuts",21).  
truck_pallet_item(1,13,"tomatoes",4). truck_pallet_item(1,13,"candies",11). truck_pallet_item(1,13,"candies",13). truck_pallet_item(1,13,"milk",4).  
truck_pallet_item(1,14,"milk",5). truck_pallet_item(1,14,"milk",6). truck_pallet_item(1,14,"milk",7). truck_pallet_item(1,14,"milk",11). truck_pallet_item(1,14,"milk",13). truck_pallet_item(1,14,"milk",14). truck_pallet_item(1,14,"milk",15). truck_pallet_item(1,14,"milk",21).  
truck_pallet_item(1,15,"bananas",21). truck_pallet_item(1,15,"milk",22). truck_pallet_item(1,15,"milk",24). truck_pallet_item(1,15,"milk",25). truck_pallet_item(1,15,"milk",26).  
truck_pallet_item(1,18,"milk",27). truck_pallet_item(1,18,"milk",28). truck_pallet_item(1,18,"milk",29). truck_pallet_item(1,18,"milk",30). truck_pallet_item(1,18,"milk",31). truck_pallet_item(1,18,"milk",32). truck_pallet_item(1,18,"milk",33). truck_pallet_item(1,18,"milk",34).  

truck_pallet_item(2,1,"bananas",5). truck_pallet_item(2,1,"tomatoes",7). truck_pallet_item(2,1,"candies",2). truck_pallet_item(2,1,"milk",1). truck_pallet_item(2,1,"milk",2). truck_pallet_item(2,1,"milk",3).  
truck_pallet_item(2,6,"candies",9). truck_pallet_item(2,6,"candies",24). truck_pallet_item(2,6,"candies",26). truck_pallet_item(2,6,"milk",8). truck_pallet_item(2,6,"milk",9). truck_pallet_item(2,6,"milk",10). truck_pallet_item(2,6,"milk",12). truck_pallet_item(2,6,"milk",16).  
truck_pallet_item(2,11,"bananas",11). truck_pallet_item(2,11,"nuts",4). truck_pallet_item(2,11,"nuts",5). truck_pallet_item(2,11,"nuts",8). truck_pallet_item(2,11,"milk",17). truck_pallet_item(2,11,"milk",18). truck_pallet_item(2,11,"milk",19). truck_pallet_item(2,11,"milk",20).  
truck_pallet_item(2,20,"tomatoes",13). truck_pallet_item(2,20,"tomatoes",14). truck_pallet_item(2,20,"tomatoes",17). truck_pallet_item(2,20,"tomatoes",19). truck_pallet_item(2,20,"nuts",20). truck_pallet_item(2,20,"nuts",22). truck_pallet_item(2,20,"milk",23). truck_pallet_item(2,20,"milk",35).  

truck_pallet_item(3,2,"bananas",13). truck_pallet_item(3,2,"bananas",15). truck_pallet_item(3,2,"bananas",19). truck_pallet_item(3,2,"nuts",6). truck_pallet_item(3,2,"nuts",9). truck_pallet_item(3,2,"nuts",19).  
truck_pallet_item(3,16,"bananas",20). truck_pallet_item(3,16,"tomatoes",1). truck_pallet_item(3,16,"tomatoes",2). truck_pallet_item(3,16,"candies",1). truck_pallet_item(3,16,"candies",3).  
truck_pallet_item(3,17,"tomatoes",5). truck_pallet_item(3,17,"tomatoes",10). truck_pallet_item(3,17,"tomatoes",11). truck_pallet_item(3,17,"tomatoes",12). truck_pallet_item(3,17,"candies",4). truck_pallet_item(3,17,"candies",6).  
truck_pallet_item(3,19,"tomatoes",18). truck_pallet_item(3,19,"tomatoes",20). truck_pallet_item(3,19,"candies",8). truck_pallet_item(3,19,"candies",14). truck_pallet_item(3,19,"candies",15). truck_pallet_item(3,19,"candies",17). truck_pallet_item(3,19,"candies",23). truck_pallet_item(3,19,"candies",27).  

truck_pallet_item(4,3,"tomatoes",9). truck_pallet_item(4,3,"candies",5). truck_pallet_item(4,3,"candies",12). truck_pallet_item(4,3,"candies",16). truck_pallet_item(4,3,"candies",18). truck_pallet_item(4,3,"candies",19). truck_pallet_item(4,3,"candies",20). truck_pallet_item(4,3,"candies",21).  
truck_pallet_item(4,5,"bananas",6). truck_pallet_item(4,5,"bananas",7). truck_pallet_item(4,5,"bananas",8). truck_pallet_item(4,5,"bananas",10). truck_pallet_item(4,5,"nuts",12).  
truck_pallet_item(4,9,"bananas",17). truck_pallet_item(4,9,"tomatoes",16). truck_pallet_item(4,9,"candies",22). truck_pallet_item(4,9,"candies",25). truck_pallet_item(4,9,"candies",28). truck_pallet_item(4,9,"candies",29). truck_pallet_item(4,9,"candies",30).  

truck_pallet_item(5,4,"bananas",2). truck_pallet_item(5,4,"bananas",12). truck_pallet_item(5,4,"bananas",14). truck_pallet_item(5,4,"bananas",16). truck_pallet_item(5,4,"candies",7). truck_pallet_item(5,4,"candies",10).  
truck_pallet_item(5,7,"bananas",18). truck_pallet_item(5,7,"nuts",1). truck_pallet_item(5,7,"nuts",2). truck_pallet_item(5,7,"nuts",3). truck_pallet_item(5,7,"nuts",7). truck_pallet_item(5,7,"nuts",10). truck_pallet_item(5,7,"nuts",11).  
truck_pallet_item(5,8,"tomatoes",3). truck_pallet_item(5,8,"nuts",13). truck_pallet_item(5,8,"nuts",14). truck_pallet_item(5,8,"nuts",15). truck_pallet_item(5,8,"nuts",16). truck_pallet_item(5,8,"nuts",17). truck_pallet_item(5,8,"nuts",18).  
truck_pallet_item(5,10,"tomatoes",6). truck_pallet_item(5,10,"tomatoes",8). truck_pallet_item(5,10,"tomatoes",15). truck_pallet_item(5,10,"nuts",23). truck_pallet_item(5,10,"nuts",24). truck_pallet_item(5,10,"nuts",25).  

%%%%% Rules ---------------------------------

pallet_items_weight(P, Count, Weight) :-
    truck_pallet_item(_, P, _, _),
    Weight = #sum{Wt, I, Q : truck_pallet_item(_, P, I, Q), item(I, _, Wt)},
    Count = #sum{1, I, Q : truck_pallet_item(_, P, I, Q)}.
    
truck_pallets_items_weight(T, Pallets, Items, Weight) :-
    truck_pallet_item(T, _, _, _),
    Weight = #sum{Wt, I, P, Q : truck_pallet_item(T, P, I, Q), item(I, _, Wt)},
    Items = #sum{1, I, P, Q : truck_pallet_item(T, P, I, Q)},
    Pallets = #sum{1, P : truck_pallet_item(T, P, _, _)}.

%%%%% Test ----------------------------------

% --- Total number of items on all trucks must match the global constraint
total_items_on_trucks(TotalItems) :- TotalItems = #sum { Count, T, P : truck_pallets_items_weight(T, P, Count, _) }.
:- total_items_on_trucks(TotalItems), TotalItems != total_quantity.

% --- Total weight of items on all trucks must match the global constraint
total_weight_assigned(TotalWeight) :- TotalWeight = #sum { Wt, T, P, I, Q : truck_pallet_item(T, P, I, Q), item(I, _, Wt) }.
:- total_weight_assigned(TotalWeight), TotalWeight != total_weight.

%%%%% Output --------------------------------

%%% #show pallet_items_weight/3.
%%% #show truck_pallets_items_weight/4.
#show total_weight_assigned/1.
#show total_items_on_trucks/1.

Output: confirms constraints are satisfied …

clingo version 5.7.2 (6bd7584d)
Reading from stdin
Solving...
Answer: 1
total_items_on_trucks(131) total_weight_assigned(145000)
SATISFIABLE

Models       : 1
Calls        : 1
Time         : 0.096s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time     : 0.000s

Observations:

  • same as Kiran:
    constraint "milk must be placed only in the fridge trucks" causes the solver to get stuck in a loop (or more precisely: I stopped before solver were able to answer)
  • same as Axel:
    no problem at all ... after adding a symmetry breaking constraint ;-)

Update (April):
I previously felt that the Clingo model above behaved and performed similarly to those shared by other posters, so I hadn’t put much effort into improving it.
However, earlier today, I came up with an idea to simplify the predicate for the items:

item(bananas, 21, 2000).  % 2kg each
item(tomatoes, 20, 1800). % 1.8kg each
item(nuts, 25, 1200).     % 1.2kg each
item(candies, 30, 1000).  % 1kg each
item(milk, 35, 200).      % 0.2kg each
  • after modifying the item predicate and adjusting the related rules and constraints, the solver produces the same output in under 0.4 sec.
  • no symmetry breaking constraint required

Output:

clingo version 5.7.2 (6bd7584d)
Reading from stdin
Solving...
Answer: 1
truck_pallet_item(3,1,candies,3) truck_pallet_item(3,1,candies,5) truck_pallet_item(5,2,bananas,1) truck_pallet_item(5,2,tomatoes,1) truck_pallet_item(5,2,tomatoes,2) truck_pallet_item(4,3,candies,8) truck_pallet_item(4,4,candies,8) truck_pallet_item(1,5,candies,2) truck_pallet_item(1,5,milk,6) truck_pallet_item(2,6,milk,8) truck_pallet_item(1,7,milk,8) truck_pallet_item(5,8,bananas,2) truck_pallet_item(5,8,nuts,5) truck_pallet_item(2,9,milk,8) truck_pallet_item(1,10,tomatoes,3) truck_pallet_item(1,10,milk,5) truck_pallet_item(4,11,tomatoes,5) truck_pallet_item(2,12,tomatoes,2) truck_pallet_item(2,12,nuts,5) truck_pallet_item(2,13,bananas,1) truck_pallet_item(2,13,bananas,4) truck_pallet_item(5,14,tomatoes,5) truck_pallet_item(1,15,tomatoes,2) truck_pallet_item(1,15,bananas,3) truck_pallet_item(5,16,nuts,7) truck_pallet_item(3,17,bananas,3) truck_pallet_item(3,17,candies,4) truck_pallet_item(3,18,nuts,4) truck_pallet_item(3,19,bananas,2) truck_pallet_item(3,19,nuts,4) truck_pallet_item(4,20,bananas,1) truck_pallet_item(4,20,bananas,4)
SATISFIABLE

Models       : 1+
Calls        : 1
Time         : 0.383s (Solving: 0.03s 1st Model: 0.03s Unsat: 0.00s)
CPU Time     : 0.000s

Here is my z3py model. It found a solution after 327s. The "sat.threads" parameter does not help here to activate multithreading. A run with a limit of 19 rather than 20 pallets required 204s.

#  import essential functions only to keep debugging list tidy
from z3 import (
    And,
    If,
    Int,
    Or,
    sat,
    set_param,
    Solver,
    Sum)
import time

started = time.time()

#  these parameters appear to have no influence
set_param("parallel.enable", True)
set_param("parallel.threads.max", 8)
set_param("sat.threads", 8)

max_trucks = 5
max_pallets = 20
fridge_trucks = 2

items = {
    "bananas": (21, 2),
    "tomatoes": (20, 1.8),
    "nuts": (25, 1.2),
    "candies": (30, 1),
    "milk": (35, 0.2)
}

debug_output = False
if debug_output:
    max_trucks = 3
    max_pallets = 2
    fridge_trucks = 1

    items = {
        "bananas": (1, 2),
        "tomatoes": (0, 1.8),
        "nuts": (2, 1.2),
        "candies": (1, 1),
        "milk": (1, 0.2)
    }

total_quantity = sum([v[0] for v in items.values()])

#  Shorthands for commonly used ranges
Trucks = range(max_trucks)
Pallets = range(max_pallets)
Items = range(total_quantity)
Bunches = range(len(items))

s = Solver()
s.set("modelpletion", True)

#  define a Z3 Int decision variable and delimit its range
def Var(name, max):
    _v = Int(name)
    s.add(0 <= _v, _v <= max)
    return _v

#  palettes are assigned to trucks
pallets_trucks = [ Var(f"pt{p}", max_trucks - 1) for p in Pallets ]
#  number of items on any pallet
pallets_items_count = [ Var(f"pc{p}", 8) for p in Pallets]
#  weight in grams on any pallet (avoiding non-integers)
pallets_weight = [ Var(f"pw{p}", 10 * 1000) for p in Pallets]

#  every bunch is assigned to one pallet
items_pallets = [ Var(f"ip{i}", max_pallets - 1) for i in Items ]

#  array to register, which bunch type an items belongs to
items_type = []

bunch_names = []

_bunch = 0
for k, v in items.items():
    bunch_names.append(k)
    for _ in range(v[0]):
        items_type.append(_bunch)
    _bunch += 1

def BunchWeight(bunch):
    #  store the weight in grams to avoid Real math
    return int(items[bunch_names[bunch]][1] * 1000)

def ItemName(item):
    return bunch_names[ItemType(item)]

def ItemType(item):
    return items_type[item]

def ItemWeight(item):
    return BunchWeight(ItemType(item))

def Iff(condition, true_val = 1):
    return If(condition, true_val, 0)
    
def B2i(condition):
    return If(condition, 1, 0)

#  return a range of item indices for a given (string) kind
def KindItems(kind):
    return (i for i in Items if ItemName(i) == kind)

#  Like KindItems() but by index rather than by kind name
def BunchItems(bunch):
    return (i for i in Items if ItemType(i) == bunch)

# Each pallet can carry no more than 8 items, with a weight limit of 10kg (= 10 * 1000g)
# Allowed variable range is delimited in Var()
for p in Pallets:
    s.add(pallets_items_count[p] ==
          Sum([B2i(p == items_pallets[i])
               for i in Items]))
    s.add(pallets_weight[p] ==
          Sum([Iff(p == items_pallets[i], ItemWeight(i))
               for i in Items]))

# Candies and nuts can often mix, so they should not be carried on the same pallet.
for c in KindItems("candies"):
    for n in KindItems("nuts"):
        s.add(items_pallets[c] != items_pallets[n])
        
# Each truck can carry no more than 30 items, with a weight limit of 40kg.
for _truck in Trucks:
    s.add(30 >= Sum([Iff(pallets_trucks[p] == _truck, pallets_items_count[p])
                     for p in Pallets]))
    s.add(40 * 1000 >= Sum([Iff(pallets_trucks[p] == _truck, pallets_weight[p])
                            for p in Pallets]))
         
# Milk must be cooled, so it should be carried by a fridge truck.
# We assume that the fridge_trucks come first in the ordering of trucks
for m in KindItems("milk"):
    for p in Pallets:
        s.add(Or(p != items_pallets[m], pallets_trucks[p] < fridge_trucks))
          
# Bananas are valuable, so each truck can carry no more than 5 bunches of bananas.
for t in Trucks:
    s.add(5 >= Sum([B2i(And(p == items_pallets[i], t == pallets_trucks[p]))
                    for p in Pallets for i in KindItems("bananas")]))

# Symmetry breaking to speedup solving process
# Items of the same kind are placed in pallets in sorted order
for _bunch in Bunches:
    #  Get quantity from dictionary
    n = items[bunch_names[_bunch]][0]
    if n > 0:
        #  The first item index for bunch
        n0 = next(BunchItems(_bunch))
        for i in range(n0, n0 + n - 1):
            s.add(items_pallets[i] <= items_pallets[i + 1])

# 
#
#  Helper functions for solution output
#
def EvalInt(model, var):
    #  All our variable can be evaluated as_long()
    return model[var].as_long()

def PalletBunches(model, pallet, bunch):
    return sum([(EvalInt(model, items_pallets[i]) == pallet) for i in BunchItems(bunch)])
    
def PalletItems(model, pallet):
    return sum([(EvalInt(model, items_pallets[i]) == pallet) for i in Items]);

def PalletWeight(model, pallet):
    return sum([(EvalInt(model, items_pallets[i]) == pallet) * ItemWeight(i) for i in Items]);

def TruckItems(model, truck):
    return sum([(EvalInt(model, pallets_trucks[p]) == truck) * PalletItems(model, p) for p in Pallets]);

def TruckWeight(model, truck):
    return sum([(EvalInt(model, pallets_trucks[p]) == truck) * PalletWeight(model, p) for p in Pallets]);

def ShowTruckPallets(model):
    print("\nPallets for trucks:")
    print("Truck   Items  Weight  Pallets assigned")
    for truck in Trucks:
        line = ""
        if TruckItems(model, truck) == 0:
            line = f"  [truck {truck+1} is empty and won't be used]"
        else:
            for pallet in Pallets:
                if (EvalInt(model, pallets_trucks[pallet]) == truck) and \
                   (EvalInt(model, pallets_items_count[pallet]) > 0):
                    line = line + f"{pallet + 1:3}"
        print(f"  {truck+1}{TruckItems(model, truck):8}{TruckWeight(model, truck):8}g {line}")
    print("")
                    
def ShowPalletBunches(model):
    print("\nBunches for pallets: ")
    print("Pallet  Items  Weight  Bunches assigned")
    for pallet in Pallets:
        line = ""
        if PalletItems(model, pallet) == 0:
            line = f"[pallet {pallet+1} is empty and won't be used]"
        else:
            for bunch in Bunches:
                if PalletBunches(model, pallet, bunch) > 0:
                    line = line + f"{PalletBunches(model, pallet, bunch)} x {bunch_names[bunch]} "
                bunch += 1
        print(f"{pallet+1:3}{PalletItems(model, pallet):8}{PalletWeight(model, pallet):8}g   {line}")  
    print("")
    
def ShowResult(model):
    ShowTruckPallets(model)
    ShowPalletBunches(model)
    
res = s.check()
if res == sat:
    ShowResult(s.model())
else:
    print("No solution. Sorry!")
    
elapsed = time.time() - started
print(f"Execution time: {int(elapsed)} seconds")  
    

The resulting solution:

Pallets for trucks:
Truck   Items  Weight  Pallets assigned
  1      30   26600g   2 10 13 15 16
  2      29   16800g   8  9 11 20
  3      16   26000g   4  6 18
  4      27   37200g   1  3  5  7
  5      29   38400g  12 14 17 19


Bunches for pallets: 
Pallet  Items  Weight  Bunches assigned
  1       7    9600g   1 x bananas 2 x tomatoes 4 x candies 
  2       4    5600g   3 x tomatoes 1 x milk 
  3       6    8800g   2 x bananas 4 x nuts 
  4       6    8000g   1 x bananas 5 x nuts 
  5       6    9800g   1 x bananas 3 x tomatoes 2 x nuts 
  6       4    8000g   4 x bananas 
  7       8    9000g   1 x bananas 7 x candies 
  8       8    1600g   8 x milk 
  9       8    1600g   8 x milk 
 10       8    2600g   1 x nuts 7 x milk 
 11       8    3600g   2 x nuts 6 x milk 
 12       7   10000g   2 x bananas 5 x nuts 
 13       8    8200g   2 x bananas 3 x nuts 3 x milk 
 14       8    9000g   1 x bananas 7 x candies 
 15       6    5200g   5 x candies 1 x milk 
 16       4    5000g   2 x tomatoes 1 x nuts 1 x milk 
 17       6    9600g   4 x tomatoes 2 x nuts 
 18       6   10000g   5 x tomatoes 1 x candies 
 19       8    9800g   1 x bananas 1 x tomatoes 6 x candies 
 20       5   10000g   5 x bananas 

Execution time: 327 seconds

I tackled the problem also with MiniZinc. That appears to be faster und all in all more suitable for this task.

%
%  This model was only solved in 4.8s by OR Tools CP-SAT 9.12.4544 
%  as MiniZinc back-end with 8 threads.
%  We could not find other solvers which succeeded in solving this.
%
array[int] of string: bunch_names = ["bananas", "tomatoes", "nuts", "candies", "milk"];
array[int] of int: bunch_counts   = [       21,         20,     25,        30,     35];
array[int] of int: bunch_weights  = [     2000,       1800,   1200,      1000,    200];

int: total_quantity = 131;
int: max_trucks = 5;
int: max_pallets = 20;
int: fridge_trucks = 2;

int: bunches = length(bunch_names);

%  Ranges for indices
set of int: Trucks = 1..max_trucks;
set of int: Pallets = 1..max_pallets;
set of int: Items = 1..total_quantity;
set of int: Bunches = 1..bunches;

%
%  Integer decision variables
%
array[Pallets] of var Trucks: pallets_trucks;
array[Pallets] of var 0..8: pallets_items_count;
array[Pallets] of var 0..10000: pallets_weights;
array[Items] of var Pallets: items_pallets;

%  Recursive hack to translate item index to item type
function Bunches: ItemType(Bunches: bunch, Items: item, int: count) =
    if (count + bunch_counts[bunch]) >= item then bunch
    else ItemType(bunch + 1, item, count + bunch_counts[bunch])
    endif;
    
function Bunches: ItemType(Items: i) = ItemType(1, i, 0);

%  Array reduces the number of calls to ItemType()
%  Have not tried if this is actually making a difference
array[Items] of Bunches: items_types = [ItemType(i) | i in Items];

function int: ItemWeight(Items: i) =
  bunch_weights[items_types[i]];

function int: Iff(bool: cond, int: true_val) =
  if cond then true_val else 0 endif;

function var int: Iff(var bool: cond, var int: true_val) =
  if cond then true_val else 0 endif;

%  Return all indices of Items matching kind
function array[int] of Items: ItemsKind(string: kind) =
  [i | i in Items where bunch_names[items_types[i]] == kind];
      
%
%  Constraints
%

%  No pallet can carry more than 8 items, with a weight limit of
%  10kg (= 10 * 1000g)
%  Limits are enforced in domain definitions of pallets_items_count[] 
%  and pallets_weights[]
constraint forall(p in Pallets) (
    (pallets_items_count[p] == sum([p == items_pallets[i] 
     | i in Items])) /\
    (pallets_weights[p] == sum([(p == items_pallets[i]) * ItemWeight(i) 
     | i in Items]))
);

%  Candies and nuts can often mix, 
%  so they should not be carried on the same pallet.
constraint forall(c in ItemsKind("candies")) (
    forall(n in ItemsKind("nuts")) (
        items_pallets[c] != items_pallets[n]
    )
);
        
%  No truck can carry more than 30 items.
constraint forall(t in Trucks) (
    30 >= sum([Iff(pallets_trucks[p] == t, pallets_items_count[p]) 
               | p in Pallets])
);

%  Weight limit per truck is 40kg = 40,000g
constraint forall(t in Trucks) (
    40000 >= sum([Iff(pallets_trucks[p] == t, pallets_weights[p]) 
                  | p in Pallets])
);

% Milk must be cooled, so it should be carried by a fridge truck.
constraint forall(m in ItemsKind("milk")) (
    forall(p in Pallets) (
        (p != items_pallets[m]) \/
        (pallets_trucks[p] <= fridge_trucks)
    )
);
          
% Bananas are valuable, so each truck can carry no more than 5 bunches of bananas.
constraint forall(t in Trucks) (
    5 >= sum([(p == items_pallets[i]) /\ 
              (t == pallets_trucks[p]) | 
              p in Pallets, i in ItemsKind("bananas")])              
);

%  To speed up the solution, we could assign the first milk item 
%  to the first pallet and this pallet to the first truck, 
%  which is a fridge truck.
%  Experiments show, that this does not give an improvement.
%  constraint pallets_trucks[1] == 1;
%  constraint items_pallets[ItemsKind("milk")[1]] = 1;

%
%  Helper functions for solution output
%
function int: PalletBunches(Pallets: p, Bunches:b) =
    count([fix(items_pallets[i]) == p | i in ItemsKind(bunch_names[b])]);
    
function int: PalletItems(Pallets: p) =
    count([fix(items_pallets[i]) == p | i in Items]);

function int: PalletWeight(Pallets: p) =
    sum([(fix(items_pallets[i]) == p) * ItemWeight(i) | i in Items]);

function int: TruckItems(Trucks: t) =
    sum([(fix(pallets_trucks[p]) == t) * PalletItems(p) | p in Pallets]);

function int: TruckWeight(Trucks: t) =
    sum([(fix(pallets_trucks[p]) == t) * PalletWeight(p) | p in Pallets]);
    
%
%  Formatted output of the solution
%
output
[ "\nPallets for trucks: "] ++
[ "\nTruck   Items  Weight  Pallets"] ++
[ if p == 1 then 
      "\n  \(t)" ++
     format(8, TruckItems(t)) ++
     format(9, TruckWeight(t)) ++ "g"
  else "" 
  endif ++ 
  if (fix(pallets_trucks[p]) == t) /\ 
     (fix(pallets_items_count[p]) > 0) then 
     format(3, p)
  else "" 
  endif 
  | t in Trucks, p in Pallets 
] ++
[ "\n\nBunches for pallets: "] ++
[ "\nPallet  Items  Weight  Bunches"] ++
[ if b == 1 then 
      "\n" ++ format(3, p) ++  
      format(8, PalletItems(p)) ++ 
      format(9, PalletWeight(p)) ++ "g  " ++
      if PalletItems(p) == 0 then
          "[pallet \(p) is empty and won't be used]"
      else ""
      endif
  else "" 
  endif ++
  if PalletBunches(p, b) > 0 then 
      "\(PalletBunches(p, b)) x " ++ bunch_names[b] ++ " " 
  else "" 
  endif 
  | p in Pallets, b in Bunches 
] ++
[ "\n\nPlausibility:"] ++
[ "\nTotal items:  \(sum([PalletItems(p) | p in Pallets]))"]  ++
[ "\nTotal weight: \(sum([PalletWeight(p) | p in Pallets]))g"] 
;

The resulting solution:
I used OR Tools as back-end solver with 8 threads.

Pallets for trucks: 
Truck   Items  Weight  Pallets
  1      29    27800g  1  9 12 16
  2      29    14000g  5 17 18 19
  3      27    39200g  2  6 10 11
  4      29    34000g  3 13 14 15
  5      17    30000g  4  7  8

Bunches for pallets: 
Pallet  Items  Weight  Bunches
  1       5    10000g  5 x bananas 
  2       5    10000g  5 x bananas 
  3       5    10000g  5 x bananas 
  4       5    10000g  5 x bananas 
  5       8     9800g  1 x bananas 4 x tomatoes 3 x milk 
  6       6    10000g  5 x tomatoes 1 x candies 
  7       6    10000g  5 x tomatoes 1 x candies 
  8       6    10000g  5 x tomatoes 1 x candies 
  9       8     9200g  1 x tomatoes 6 x nuts 1 x milk 
 10       8     9600g  8 x nuts 
 11       8     9600g  8 x nuts 
 12       8     4600g  3 x nuts 5 x milk 
 13       8     8000g  8 x candies 
 14       8     8000g  8 x candies 
 15       8     8000g  8 x candies 
 16       8     4000g  3 x candies 5 x milk 
 17       8     1600g  8 x milk 
 18       8     1600g  8 x milk 
 19       5     1000g  5 x milk 
 20       0        0g  [pallet 20 is empty and won't be used]

Plausibility:
Total items:  131
Total weight: 145000g
----------
==========
Finished in 4s 830msec.

This is my Z3py model for the problem. The model ran in 519 seconds on my machine.

from z3 import (
    And, If, IntSort, BoolSort, Function, Solver, Sum, Not, Implies, sat
)
import time

started = time.time()

def get_packing(typ, qty):
    packing = {
        "bananas": "bunch",
        "tomatoes": "bunch",
        "nuts": "bag",
        "candies": "bag",
        "milk": "pack"
    }
    packing_text = (packing[typ] + "s" if packing[typ] != "bunch" else packing[typ] + "es") if qty > 1 else packing[typ]
    return f"{qty} {packing_text}"

items = {
    "bananas": (21, 2),
    "tomatoes": (20, 1.8),
    "nuts": (25, 1.2),
    "candies": (30, 1),
    "milk": (35, 0.2)
}

total_quantity = 131
max_trucks = 5
max_pallets = 20

# Mapping items to specific ranges
'''
    Dictionary to create global mappig for items
    {
        'bananas': (0, 21),
        'tomatoes': (21, 41),
        'nuts': (41, 66),
        'candies': (66, 96),
        'milk': (96, 131)
    }
'''
item_ranges = {}
current_index = 0
for t, (count, weight) in items.items():
    item_ranges[t] = (current_index, current_index + count)
    current_index += count

# Mapping item to corresponding type and weight
'''
    Each item is mapped its weight and type for easy reference.
'''
item_type = {}
item_weight = {}
for t, (count, weight) in items.items():
    start, end = item_ranges[t]
    for i in range(start, end):
        item_type[i] = t
        item_weight[i] = weight

p = Function('p', IntSort(), IntSort(), BoolSort()) # confirms if item is in pallet
t = Function('t', IntSort(), IntSort(), BoolSort()) # confirms if pallet is in truck
fridge = Function('fridge', IntSort(), BoolSort())  # confirms if it's a fridge truck

s = Solver()

# Each item must be on exactly one pallet.
for i in range(total_quantity):
    s.add(Sum([If(p(i, j), 1, 0) for j in range(max_pallets)]) == 1)

# Each pallet used assigned to exactly truck.
for j in range(max_pallets):
    s.add(Sum([If(t(j, m), 1, 0) for m in range(max_trucks)]) <= 1) # max 1 truck
    s.add(Implies(Sum([If(p(i, j), 1, 0) for i in range(total_quantity)]) > 0,
                  Sum([If(t(j, m), 1, 0) for m in range(max_trucks)]) == 1)) 

# Set Fridge Trucks
s.add(Sum([If(fridge(m), 1, 0) for m in range(max_trucks)]) == 2)

# Set Pallet Capacity
'''
    Total number of items should be less than 8.
    Total weight of items on pallet, derived from the wieght mapping, 
    should be less than 10.
'''
for j in range(max_pallets):
    s.add(Sum([If(p(i, j), 1, 0) for i in range(total_quantity)]) <= 8)
    s.add(Sum([If(p(i, j), item_weight[i], 0) for i in range(total_quantity)]) <= 10)

# Candies and nuts cannot be on the same pallet.
'''
    Iterated through the candy and nuts indices to check if both of them
    are not in the same pallet
'''
candies_range = range(item_ranges["candies"][0], item_ranges["candies"][1])
nuts_range = range(item_ranges["nuts"][0], item_ranges["nuts"][1])
for j in range(max_pallets):
    for ci in candies_range:
        for ni in nuts_range:
            s.add(Not(And(p(ci, j), p(ni, j))))

# Set Truck Capacity
'''
    The total quantity and weight of the objects in each pallet that is 
    assigned to the respective truck is checked to satisfy the constraint.
'''
for m in range(max_trucks):
    s.add(Sum([If(t(j, m), Sum([If(p(i, j), 1, 0) for i in range(total_quantity)]), 0)
               for j in range(max_pallets)]) <= 30)
    s.add(Sum([If(t(j, m), Sum([If(p(i, j), item_weight[i], 0) for i in range(total_quantity)]), 0)
               for j in range(max_pallets)]) <= 40)

# Milk must be on a fridge truck.
'''
    Directly assigning Milk to Fridge trucks was causing my solver to be heavy.
    So I decided on going on with the idea that if milk is present in a pallet,
    then the pallet must be assigned to the fridge truck.
'''
milk_range = range(item_ranges["milk"][0], item_ranges["milk"][1])
for j in range(max_pallets):
    milk_on_pallet = Sum([If(p(i, j), 1, 0) for i in milk_range])
    for m in range(max_trucks):
        s.add(Implies(And(milk_on_pallet > 0, t(j, m)), fridge(m)))

# Each truck can carry no more than 5 bunches of bananas.
'''
    Sum of all the bananas in all the pallets assigned to the truck is
    constrained to fall below 5.
'''
banana_range = range(item_ranges["bananas"][0], item_ranges["bananas"][1])
for m in range(max_trucks):
    s.add(Sum([If(t(j, m), Sum([If(p(i, j), 1, 0) for i in banana_range]), 0)
               for j in range(max_pallets)]) <= 5)

if s.check() == sat:
    model = s.model()
    print("Model present")

    total_output = {item: 0 for item in items.keys()}
    with open("model.txt", "w") as f:
        for m in range(max_trucks):
            truck_type = "Fridge" if model.evaluate(fridge(m)) else "Normal"
            print(f"\n{truck_type} Truck {m+1}:", file=f)
            pallet_num = 0
            for j in range(max_pallets):
                if model.evaluate(t(j, m)):
                    pallet_num += 1
                    pallet_items = {item: 0 for item in items.keys()}
                    for i in range(total_quantity):
                        if model.evaluate(p(i, j)):
                            typ = item_type[i]
                            pallet_items[typ] += 1
                            total_output[typ] += 1
                    print(f"  Pallet {pallet_num}:", file=f)
                    for typ, count in pallet_items.items():
                        if count > 0:
                            print(f"    {typ}: {get_packing(typ, count)}", file=f)
        print("\n\nTotal Output:", total_output, file=f)
else:
    print("Solver Unsatisfiable")


elapsed = time.time() - started
print(f"Execution time: {int(elapsed)} seconds")  

This is the model produced by the solver.

----------------------------  MODEL PRODUCED  ----------------------------
Normal Truck 1:
  Pallet 1:
    bananas: 2 bunches
    tomatoes: 1 bunch
    nuts: 3 bags
  Pallet 2:
    bananas: 1 bunch
    tomatoes: 1 bunch
    candies: 6 bags
  Pallet 3:
    bananas: 2 bunches
    tomatoes: 1 bunch
    candies: 4 bags
  Pallet 4:
    tomatoes: 1 bunch
    nuts: 6 bags

Fridge Truck 2:
  Pallet 1:
    milk: 8 packs
  Pallet 2:
    nuts: 6 bags
    milk: 2 packs
  Pallet 3:
    milk: 8 packs
  Pallet 4:
    bananas: 1 bunch
    tomatoes: 2 bunches
    nuts: 1 bag
    milk: 2 packs

Fridge Truck 3:
  Pallet 1:
    milk: 8 packs
  Pallet 2:
    candies: 7 bags
    milk: 1 pack
  Pallet 3:
    bananas: 4 bunches
    tomatoes: 1 bunch
    milk: 1 pack
  Pallet 4:
    bananas: 1 bunch
    tomatoes: 1 bunch
    nuts: 1 bag
    milk: 5 packs

Normal Truck 4:
  Pallet 1:
    bananas: 2 bunches
    tomatoes: 1 bunch
    candies: 1 bag
  Pallet 2:
    bananas: 1 bunch
    tomatoes: 3 bunches
    nuts: 2 bags
  Pallet 3:
    bananas: 2 bunches
    tomatoes: 1 bunch
    nuts: 3 bags

Normal Truck 5:
  Pallet 1:
    tomatoes: 2 bunches
    candies: 6 bags
  Pallet 2:
    bananas: 4 bunches
    tomatoes: 1 bunch
  Pallet 3:
    bananas: 1 bunch
    tomatoes: 2 bunches
    nuts: 3 bags
  Pallet 4:
    tomatoes: 2 bunches
    candies: 6 bags

Total Output: {'bananas': 21, 'tomatoes': 20, 'nuts': 25, 'candies': 30, 'milk': 35}
------------------------------------------------------------------------------------
发布评论

评论列表(0)

  1. 暂无评论