A regional tobacco distribution company operates three distribution centers located in different zones of a metropolitan area to serve 15 retail outlets. The company needs to optimize its weekly delivery operations to minimize total transportation costs while satisfying regulatory constraints and customer demands.

The three distribution centers have different storage capacities and operational costs. Center A can handle up to 800 units per week with a fixed operating cost of $2,500, Center B can handle up to 600 units per week with a fixed cost of $2,000, and Center C can handle up to 500 units per week with a fixed cost of $1,800. Each retail outlet has specific weekly demand requirements ranging from 45 to 120 units, and due to regulatory compliance, each outlet must receive deliveries from exactly one distribution center to maintain proper tracking and accountability.

The transportation cost varies based on the distance between distribution centers and retail outlets, ranging from $8 to $25 per unit delivered. Additionally, there are regulatory constraints that limit the maximum number of outlets each distribution center can serve - Center A can serve at most 7 outlets, Center B can serve at most 6 outlets, and Center C can serve at most 5 outlets. The company must also ensure that the total demand assigned to each center does not exceed its capacity, and all retail outlets must be served to maintain market coverage.

| Outlet | Demand | Cost from A | Cost from B | Cost from C |
|--------|--------|-------------|-------------|-------------|
| 1      | 85     | $12         | $18         | $22         |
| 2      | 67     | $15         | $11         | $25         |
| 3      | 92     | $20         | $14         | $16         |
| 4      | 78     | $13         | $19         | $23         |
| 5      | 105    | $17         | $12         | $20         |
| 6      | 56     | $25         | $16         | $14         |
| 7      | 120    | $14         | $21         | $18         |
| 8      | 73     | $16         | $13         | $24         |
| 9      | 89     | $19         | $15         | $17         |
| 10     | 95     | $11         | $22         | $19         |
| 11     | 62     | $23         | $17         | $15         |
| 12     | 84     | $18         | $14         | $21         |
| 13     | 76     | $21         | $20         | $13         |
| 14     | 45     | $24         | $25         | $16         |
| 15     | 58     | $22         | $23         | $12         |

Problem type: ILP (Medium: 48 variables, 66 constraints, 231 nonzeros)

Mathematical model:
Set:
1. Distribution Centers
The set of distribution centers, D = {A, B, C}
2. Retail Outlets
The set of retail outlets, R = {1, 2, 3, ..., 15}

Parameter:
1. Center Capacity
Capacity[A] = 800, Capacity[B] = 600, Capacity[C] = 500
2. Fixed Operating Cost
FixedCost[A] = 2500, FixedCost[B] = 2000, FixedCost[C] = 1800
3. Outlet Demand
Demand = [85, 67, 92, 78, 105, 56, 120, 73, 89, 95, 62, 84, 76, 45, 58]
4. Transportation Cost per Unit
TransportCost[i][j] for center i ∈ D and outlet j ∈ R (as shown in the table above)
5. Maximum Outlets per Center
MaxOutlets[A] = 7, MaxOutlets[B] = 6, MaxOutlets[C] = 5

Decision variable:
1. Center Operation
Binary variable x_i ∈ {0, 1} for all i ∈ D, where x_i = 1 if distribution center i is operated, and x_i = 0 otherwise
2. Assignment
Binary variable y_{ij} ∈ {0, 1} for all i ∈ D, j ∈ R, where y_{ij} = 1 if outlet j is served by center i, and y_{ij} = 0 otherwise

Objective:
Minimize total cost including fixed operating costs and transportation costs
min: Σ_{i∈D} FixedCost_i × x_i + Σ_{i∈D} Σ_{j∈R} TransportCost_{ij} × Demand_j × y_{ij}

Constraint:
1. Each outlet must be served by exactly one distribution center
Σ_{i∈D} y_{ij} = 1, ∀j ∈ R
2. Center capacity constraint - total demand assigned to each center cannot exceed its capacity
Σ_{j∈R} Demand_j × y_{ij} ≤ Capacity_i × x_i, ∀i ∈ D
3. Maximum number of outlets per center constraint
Σ_{j∈R} y_{ij} ≤ MaxOutlets_i × x_i, ∀i ∈ D
4. Logical constraint - outlets can only be assigned to operating centers
y_{ij} ≤ x_i, ∀i ∈ D, ∀j ∈ R

Type:
Binary, Linear, Linear
ILP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_tobacco_distribution(
    centers=['A', 'B', 'C'],
    outlets=list(range(1, 16)),
    capacity={'A': 800, 'B': 600, 'C': 500},
    fixed_cost={'A': 2500, 'B': 2000, 'C': 1800},
    demand=[85, 67, 92, 78, 105, 56, 120, 73, 89, 95, 62, 84, 76, 45, 58],
    max_outlets={'A': 7, 'B': 6, 'C': 5},
    transport_cost_data=None
):
    """
    Solve the multi-depot tobacco distribution network optimization problem.
    """
    if transport_cost_data is None:
        transport_cost = {
            'A': [12, 15, 20, 13, 17, 25, 14, 16, 19, 11, 23, 18, 21, 24, 22],
            'B': [18, 11, 14, 19, 12, 16, 21, 13, 15, 22, 17, 14, 20, 25, 23],
            'C': [22, 25, 16, 23, 20, 14, 18, 24, 17, 19, 15, 21, 13, 16, 12]
        }
    else:
        transport_cost = transport_cost_data

    model = gp.Model("tobacco_distribution")

    x = model.addVars(centers, vtype=GRB.BINARY, name="center_operation")
    y = model.addVars(centers, outlets, vtype=GRB.BINARY, name="assignment")

    fixed_costs = gp.quicksum(fixed_cost[i] * x[i] for i in centers)
    transport_costs = gp.quicksum(
        transport_cost[i][j - 1] * demand[j - 1] * y[i, j]
        for i in centers for j in outlets
    )
    model.setObjective(fixed_costs + transport_costs, GRB.MINIMIZE)

    for j in outlets:
        model.addConstr(gp.quicksum(y[i, j] for i in centers) == 1)

    for i in centers:
        model.addConstr(gp.quicksum(demand[j - 1] * y[i, j] for j in outlets) <= capacity[i] * x[i])
        model.addConstr(gp.quicksum(y[i, j] for j in outlets) <= max_outlets[i] * x[i])
        for j in outlets:
            model.addConstr(y[i, j] <= x[i])

    model.optimize()

    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.objVal}
    else:
        return {"status": f"{model.status}"}


if __name__ == "__main__":
    result = solve_tobacco_distribution()
    print(result)


Solution status: OPTIMAL
Optimal objective value: 21922