RapidLink Logistics, a regional delivery company, needs to optimize its daily outbound operations from its main distribution hub. Today, they have 3 delivery trucks of varying capacities and 8 high-priority parcels that must be shipped. The goal is to assign each of the 8 parcels to exactly one of the three trucks to maximize the total revenue for the day.

The total revenue is composed of two parts: a standard shipping fee for each parcel and a significant synergy bonus that is gained when specific pairs of parcels are placed in the *same* truck. These bonuses arise because certain parcels are headed to the same dense urban block or large corporate campus, allowing for a much more efficient final-mile delivery.

The capacities of the three available trucks are:
- Truck 1: 100 kg
- Truck 2: 120 kg
- Truck 3: 80 kg

The details for the 8 high-priority parcels are listed below:
| Parcel ID | Weight (kg) | Base Revenue ($) |
| :--- | :--- | :--- |
| 1 | 35 | 50 |
| 2 | 45 | 75 |
| 3 | 25 | 40 |
| 4 | 50 | 80 |
| 5 | 30 | 60 |
| 6 | 40 | 65 |
| 7 | 20 | 35 |
| 8 | 55 | 90 |

Additionally, the logistics team has identified specific pairs of parcels that generate a synergy bonus if shipped in the same truck. These pairings and their associated bonuses are:
| Parcel Pair | Synergy Bonus ($) | Reason |
| :--- | :--- | :--- |
| (1, 3) | 25 | Same residential complex |
| (2, 5) | 30 | Same industrial park |
| (2, 6) | 20 | Neighboring corporate offices |
| (4, 8) | 40 | Both are heavy-lift items for one client |
| (5, 7) | 22 | Same downtown skyscraper |

The company must decide which parcels go into which truck, respecting the weight capacity of each truck, to achieve the maximum possible total revenue.

Problem type: NLP (Small: 24 variables, 11 constraints, 48 nonzeros)

Mathematical model:
Set:
1. Parcels
The set of parcels, \( I = \{1, 2, ..., 8\} \)
2. Trucks
The set of trucks, \( J = \{1, 2, 3\} \)
3. Synergy Pairs
The set of parcel pairs with a synergy bonus, \( P = \{(1, 3), (2, 5), (2, 6), (4, 8), (5, 7)\} \)

Parameter:
1. Parcel Weights (kg)
\( w = [35, 45, 25, 50, 30, 40, 20, 55] \)
2. Base Revenues ($)
\( r = [50, 75, 40, 80, 60, 65, 35, 90] \)
3. Truck Capacities (kg)
\( C = [100, 120, 80] \)
4. Synergy Bonuses ($)
\( s_{1,3}=25, s_{2,5}=30, s_{2,6}=20, s_{4,8}=40, s_{5,7}=22 \) (and \( s_{ik}=0 \) for all other pairs)

# Decision variable
# x_ij: A binary variable that indicates the assignment of parcels to trucks.
Decision variable:
1. AssignmentVariable
Binary variable,  \( x_{ij} \in \{0, 1\} \) for all \( i \in I, j \in J \), where \( x_{ij} = 1 \) if parcel \( i \) is assigned to truck \( j \), and 0 otherwise.

Objective:
Maximize total revenue
# To maximize the total revenue, which is the sum of the base revenues for all parcels 
# plus the sum of all achieved synergy bonuses. A bonus for pair (i,k) is achieved if
# both parcels are assigned to the same truck j.
max: \( \sum_{i \in I} \sum_{j \in J} r_i \cdot x_{ij} + \sum_{j \in J} \sum_{(i,k) \in P} s_{ik} \cdot x_{ij} \cdot x_{kj} \)

# Constraint
Constraint:
1. Parcel Assignment
# Each parcel must be assigned to exactly one truck.
\( \sum_{j \in J} x_{ij} = 1, \quad \forall i \in I \)
2. Truck Capacity
# For each truck, the sum of the weights of the parcels assigned to it must not exceed its capacity.
\( \sum_{i \in I} w_i \cdot x_{ij} \leq C_j, \quad \forall j \in J \)

Type:
Integer, Non-linear, Linear
NLP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_logistics_optimization(
    parcels=[1, 2, 3, 4, 5, 6, 7, 8],
    trucks=[1, 2, 3],
    weights={1: 35, 2: 45, 3: 25, 4: 50, 5: 30, 6: 40, 7: 20, 8: 55},
    base_revenues={
        1: 50,
        2: 75,
        3: 40,
        4: 80,
        5: 60,
        6: 65,
        7: 35,
        8: 90
    },
    capacities={1: 100, 2: 120, 3: 80},
    synergy_bonuses={
        (1, 3): 25,
        (2, 5): 30,
        (2, 6): 20,
        (4, 8): 40,
        (5, 7): 22
    }
):
    """
    Models and solves the quadratic multiple knapsack problem for RapidLink Logistics
    """
    # --- 1. Model Creation ---
    model = gp.Model("QuadraticKnapsackLogistics")

    # --- 2. Decision Variables ---
    # x[i, j] = 1 if parcel i is assigned to truck j, 0 otherwise.
    x = model.addVars(parcels, trucks, vtype=GRB.BINARY, name="assign")

    # --- 3. Objective Function ---
    # The total revenue is the sum of base revenues plus synergy bonuses.
    synergy_revenue = gp.quicksum(synergy_bonuses[i, k] * x[i, j] * x[k, j]
                                    for (i, k) in synergy_bonuses
                                    for j in trucks)
    sum_base_revenue = gp.quicksum(base_revenues[i] for i in parcels)

    model.setObjective(synergy_revenue + sum_base_revenue, GRB.MAXIMIZE)

    # --- 4. Constraints ---

    # Constraint 1: Each parcel must be assigned to exactly one truck.
    for i in parcels:
        model.addConstr(gp.quicksum(x[i, j] for j in trucks) == 1,
                        name=f"parcel_assign_{i}")

    # Constraint 2: The weight in each truck cannot exceed its capacity.
    for j in trucks:
        model.addConstr(gp.quicksum(weights[i] * x[i, j] for i in parcels)
                        <= capacities[j],
                        name=f"truck_capacity_{j}")

    # --- 5. Solve the Model ---
    model.optimize()

    # --- 6. Return Results ---
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.ObjVal}
    else:
        return {"status": f"{model.status}"}


# Run the solver function
if __name__ == "__main__":
    result = solve_logistics_optimization()
    print(result)


Solution status: OPTIMAL
Optimal objective value: 537