A small-scale bakery operates in four towns: Greenville, Springfield, Riverside, and Hilltop. The bakery produces fresh bread, which is then delivered to local stores located in Maplewood, Oakdale, Pineville, Cedarhurst, and Brookside. The number of loaves of bread available at each bakery is provided in Table 1. Each store requires a specific number of loaves to meet daily customer demand, as shown in Table 2. The distances (in kilometers) between the bakeries and stores are given in Table 3.  Assuming the delivery cost (in USD) for each loaf of bread is calculated as the square root of the distance between the origin and destination towns, determine the optimal delivery schedule that minimizes total transportation costs while meeting all store requirements.  

Table 1: Bread Availability at Bakeries  
| Bakery       | Loaves Available |  
|--------------|------------------|  
| Greenville   | 200              |  
| Springfield  | 150              |  
| Riverside    | 250              |  
| Hilltop      | 180              |  

Table 2: Bread Requirements at Stores  
| Store        | Loaves Required |  
|--------------|-----------------|  
| Maplewood    | 120             |  
| Oakdale      | 100             |  
| Pineville    | 130             |  
| Cedarhurst   | 90              |  
| Brookside    | 80              |  

Table 3: Distances Between Bakeries and Stores (km)  
| From / To    | Maplewood | Oakdale | Pineville | Cedarhurst | Brookside |  
|--------------|-----------|---------|-----------|------------|-----------|  
| Greenville   | 10        | 15      | 20        | 25         | 30        |  
| Springfield  | 12        | 8       | 18        | 22         | 28        |  
| Riverside    | 14        | 10      | 16        | 20         | 26        |  
| Hilltop      | 16        | 12      | 14        | 18         | 24        |

Problem type: ILP (Small: 20 variables, 9 constraints, 40 nonzeros)

Mathematical model:
Set:
1. Bakery
The set of bakeries, \( B = \{1, 2, ..., BakeryNum\} \)
2. Store
The set of stores, \( S = \{1, 2, ..., StoreNum\} \)

Parameter:
1. BakeryNum
4
2. StoreNum
5
3. BakerySupply
[200, 150, 250, 180]
4. StoreDemand
[120, 100, 130, 90, 80]
5. ShippingDistance
[
    [10, 15, 20, 25, 30],
    [12, 8, 18, 22, 28],
    [14, 10, 16, 20, 26],
    [16, 12, 14, 18, 24]
]
6. ShippingCost
[
    [sqrt(10), sqrt(15), sqrt(20), sqrt(25), sqrt(30)],
    [sqrt(12), sqrt(8), sqrt(18), sqrt(22), sqrt(28)],
    [sqrt(14), sqrt(10), sqrt(16), sqrt(20), sqrt(26)],
    [sqrt(16), sqrt(12), sqrt(14), sqrt(18), sqrt(24)]
]

Decision variable:
1. ShipAmount
Integer variable, \( ShipAmount_{b,s} \forall b \in B, s \in S \), where \( ShipAmount_{b,s} \) is the amount of bread shipped from bakery \( b \) to store \( s \).

Objective:
1. Minimize the total transportation cost required to deliver the bread.
min: \sum_{b \in B} \sum_{s \in S} ShippingCost[b][s] * ShipAmount[b][s]

Constraint:
1. Bakery supply constraint.
\sum_{s \in S} ShipAmount[b][s] \leq BakerySupply[b] \forall b \in B
2. Store demand constraint.
\sum_{b \in B} ShipAmount[b][s] = StoreDemand[s] \forall s \in S

Type:
Integer, Linear, Linear
ILP


Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB
import math


def solve_bakery_distribution(
    BakerySupply=[200, 150, 250, 180],
    StoreDemand=[120, 100, 130, 90, 80],
    ShippingDistance=[[10, 15, 20, 25, 30], [12, 8, 18, 22, 28],
                      [14, 10, 16, 20, 26], [16, 12, 14, 18, 24]]):
    """
    Solves the bakery distribution (transportation) problem.
    """
    # --- 1. Model Creation ---
    model = gp.Model("Bakery Distribution Optimization")

    # --- 2. Parameters & Sets ---
    BakeryNum = len(BakerySupply)
    StoreNum = len(StoreDemand)
    Bakeries = range(BakeryNum)
    Stores = range(StoreNum)

    # Calculate shipping costs with square roots
    ShippingCost = [[math.sqrt(dist) for dist in row]
                    for row in ShippingDistance]

    # --- 3. Decision Variables ---
    ShipAmount = model.addVars(Bakeries,
                               Stores,
                               vtype=GRB.INTEGER,
                               name="ShipAmount")

    # --- 4. Objective Function ---
    # Minimize total transportation cost
    model.setObjective(
        gp.quicksum(ShippingCost[b][s] * ShipAmount[b, s] for b in Bakeries
                    for s in Stores), GRB.MINIMIZE)

    # --- 5. Constraints ---
    # Constraint 1: Bakery supply constraint
    model.addConstrs(
        (gp.quicksum(ShipAmount[b, s] for s in Stores) <= BakerySupply[b]
         for b in Bakeries),
        name="BakerySupply")

    # Constraint 2: Store demand constraint
    model.addConstrs(
        (gp.quicksum(ShipAmount[b, s] for b in Bakeries) == StoreDemand[s]
         for s in Stores),
        name="StoreDemand")

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

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


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

Solution status: OPTIMAL
Optimal objective value: 1947.670525618807