← All posts

Set Cover Meets Ant Colony: How We Optimized Multi-Store Delivery Routes

Set Cover Meets Ant Colony: How We Optimized Multi-Store Delivery Routes

Last semester I co-authored a paper on delivery route optimization that got published in the Journal of Robotics and Control. The core question: if a user’s cart has items spread across five different nearby stores, what’s the cheapest, fastest way to collect everything and deliver it?

This post is a deeper walkthrough of what we actually built and why we made the choices we did — more than what fits in a paper’s page limit.


The problem nobody talks about

Most delivery optimization research assumes a single warehouse. Real quick-commerce is messier: a user orders pasta, medicine, and phone cable. Those three items might be in three different stores within 2km. The system has to decide which stores to visit and in what order — and those are two fundamentally different problems stacked on top of each other.

We formalized this as two stages:

  1. Store selection — find the minimal subset of stores that collectively stock every item in the cart
  2. Route optimization — find the cheapest path through those stores to the delivery address

Stage 1 is a Set Cover Problem. Stage 2 is a Traveling Salesman Problem. Both are NP-hard. Great.


Stage 1: Modeling store selection as Set Cover

Given a set of required items I = {i₁, i₂, ..., iₘ} and nearby stores S = {s₁, s₂, ..., sₙ}, we build an availability matrix A where A[s][i] = 1 if store s stocks item i.

The goal is to find the smallest subset S* ⊆ S such that every item in I is covered by at least one store in S*, while also minimizing total travel cost.

We use a greedy set cover approach: start with an empty S*, iteratively add whichever store covers the most currently uncovered items, break ties by proximity to the delivery address.

Here’s the core of that logic:

JS  Greedy Set Cover — store selection

Notice how the greedy approach skips MegaStore (which covers everything, cost 8) in favor of QuickMart + HealthPlus (covers everything, cost 5). This is the classical approximation — it’s guaranteed to be within O(log n) of optimal, which is the best we can do for NP-hard problems with a polynomial algorithm.


Stage 2: Route optimization as TSP

Once we have S*, we need the shortest path through those stores to the delivery address. This is a Traveling Salesman Problem on a small graph (usually 2-5 nodes), so even brute force is fast.

The cost matrix captures inter-store distances plus the distance from each store to the delivery location d. We want to minimize:

minimize Σ Cost(sᵢ, sⱼ) for (sᵢ,sⱼ) ∈ route

For small |S*|, nearest-neighbor heuristic gets us close to optimal:

JS  Nearest-Neighbor TSP — route optimization

The Ant Colony Optimization approach

The classical two-stage method gives us a deterministic, predictable answer. But as the number of deliveries grows, it struggles — the greedy set cover can miss better combinations, and the TSP heuristic doesn’t adapt to constraints like traffic congestion or time windows.

ACO takes a completely different approach. It simulates a colony of ants, each building a route probabilistically. Ants that find better routes deposit more pheromone, biasing future ants toward those paths. Over hundreds of iterations, the colony converges on a near-optimal solution.

The key formula is the transition probability — how likely ant k is to move from city i to city j:

p_ij^k(t) = [τ_ij(t)]^α · [η_ij]^β  /  Σ [τ_ij(t)]^α · [η_ij]^β

Where τ_ij is pheromone on edge (i,j), η_ij = 1/distance is visibility, and α, β control the tradeoff between following pheromone vs. picking nearby nodes.

Pheromone evaporates over time (controlled by ρ) so bad paths don’t get permanently reinforced:

τ_ij(t+n) = ρ · τ_ij(t) + Δτ_ij(t)

Here’s a stripped-down simulation to show how pheromone reinforcement works:

JS  ACO pheromone reinforcement — watch short paths win

Run this and watch: the shorter depot→QuickMart edge accumulates pheromone faster than the longer routes, even though all edges start equal. This emergent bias is what guides the colony toward good solutions without anyone explicitly programming “prefer short edges.”


Adding congestion as an independent parameter

One of the more interesting things we did was introduce traffic congestion as a weighted parameter on each node. We generated a synthetic heatmap where certain areas have high congestion levels, then ran both algorithms on it.

The result was surprising: in congested scenarios, the classical model actually beat ACO on cost. The classical model follows a fixed, mathematically computed path that sidesteps congested nodes by construction. ACO’s pheromone trails, built before congestion data is fully incorporated, can get “stuck” reinforcing paths that happen to run through congested zones.

This gave us the main practical finding of the paper:

JS  Congestion-aware cost — why environment matters

What the simulations showed

We ran both approaches on 100 simulated deliveries in Python and measured average delivery time and total cost at different scales.

The findings:

Classical (Set Cover + TSP)

  • Fast and exact for small delivery counts
  • Average delivery time increases steeply as volume grows
  • Wins on cost in high-congestion environments
  • No real-time adaptability

ACO

  • Consistently better average delivery time at high volumes
  • Cost scales more gracefully
  • Adapts dynamically via pheromone updates
  • Struggles above ~80 nodes when time window constraints are strict (ACO2 variant)

Neither approach dominates across all conditions. The paper concludes with a proposal for a hybrid model controlled by a parameter θ that selects the algorithm based on detected delivery environment — use classical for low-volume or high-congestion scenarios, ACO for large-scale or dynamic ones.


What I’d do differently

The congestion parameter was static — we baked it into the cost matrix before running either algorithm. A real system would need live traffic data updating the weights mid-route. That’s the natural next step: integrating a real-time traffic API and testing how ACO’s pheromone evaporation rate responds to sudden congestion spikes vs. how quickly a classical re-plan can compute a new optimal.

The paper’s code and simulation data are available if you want to dig into the Python implementation.