How I Ruined F1's Schedule
June 2024
Formula 1 travels the world. The 2024 calendar featured 24 races across six continents, from Bahrain in March to Abu Dhabi in December. The FIA shapes this calendar around broadcast windows, venue permits, and commercial contracts. What it only partially account for is travel efficiency, with teams and drivers complaining about the large distances every year.
That raised a question worth a weekend of work: just how badly could the schedule be designed? Not just bad, but mathematically worst-case worse. Given exactly the 24 venues on the 2024 calendar, what ordering maximizes total travel distance?
Gathering Required Data
Before building any model, I needed two inputs: the list of race locations and the great-circle distances between every pair of them. The calendar is public and shared on the F1 website. The 24 venues are Sakhir, Jeddah, Melbourne, Suzuka, Shanghai, Miami, Imola, Monaco, Montreal, Barcelona, Spielberg, Silverstone, Budapest, Spa, Zandvoort, Monza, Baku, Singapore, Austin, Mexico City, São Paulo, Las Vegas, Lusail, and Yas Marina.
For distances, I scraped geographic coordinates for each venue and computed the great-circle distance between every pair. Assuming a spherical Earth, an approximation that introduces roughly 0.3% error, the first step is to convert each latitude/longitude pair into a three-dimensional unit vector. With \(\theta\) as the longitude and \(\phi = 90^\circ - \text{latitude}\):
For two cities A and B with unit position vectors \(\hat{r}_A\) and \(\hat{r}_B\), the dot product gives the cosine of the central angle \(\alpha\) between them:
By the arc-length formula \(s = r\alpha\), the great-circle distance is obtained by multiplying the central angle by Earth's radius \(r_E = 6{,}371\) km:
Applying this to all \(\binom{24}{2} = 276\) city pairs yields a complete symmetric \(24 \times 24\) distance matrix \(D\), where \(D_{ij}\) is the great-circle distance in kilometers from city \(i\) to city \(j\).
Initial Model
My first attempt was a Maximum-Cost Flow model. The Min-Cost Flow (MCF) formulation is a well-studied network optimization problem. Given a directed graph, route flow from sources to sinks while minimizing total travel cost. I had used it in coursework and research, and it scales very well (it has an exact LP relaxation for single source/sink pair). I adapted it by flipping the objective to maximize instead of minimize.
I built a graph with the 24 venues as nodes and a directed edge between every ordered pair. The incidence matrix \(A\) encodes the topology: \(A_{i,j} = -1\) if edge \(j\) leaves node \(i\), and \(A_{i,j} = 1\) if edge \(j\) enters node \(i\). The formulation is:
Here \(E\) is the set of all edges, \(V\) is the set of nodes, \(s\) and \(t\) are the source and terminal cities, \(d_j\) is the distance along edge \(j\), and \(f_j\) is the binary flow variable. Since we don't know which origin/destination pair \((s, t)\) gives the longest path in advance, we loop over every possibility, all \(24 \times 23 = 552\) of them, modifying only the right-hand side between solves rather than rebuilding the model each time.
"Why isn't it working?"
The model returned solutions that were clearly wrong once plotted. The culprit was sub-tours, or individual disconnected cycles that are nowhere near the main route.
The flow-balance constraints only enforce that the number of edges entering each intermediate node equals the number leaving. They say nothing about connectivity. A solution can satisfy all constraints while containing two or more disjoint loops. For example, a small European cycle (Imola → Monaco → Barcelona → Imola) running simultaneously with a separate Pacific cycle (Melbourne → Singapore → Suzuka → Melbourne), with neither loop connected to the other. The solver happily accepts both as feasible.
I tried patching this by adding constraints that forbid traveling along both \(i \to j\) and \(j \to i\) simultaneously. This eliminated two-city loops but did nothing to prevent larger sub-tours. Adding all possible subtours of length 2-23 would require combinatorially many constraints, intractable in this context. A different formulation was needed.
Traveling Salesman Problem
The Traveling Salesman Problem (TSP) is purpose-built for exactly this situation. It seeks a Hamiltonian cycle, a closed tour that visits every city exactly once before returning to the start. Unlike the flow formulation, it prevents sub-tours with some slight tweaks. While the classical TSP minimizes tour length, a more practical problem than what we are trying to achieve, but the formulation is otherwise identical.
Variables and objective
Let \(x_{ij} \in \{0, 1\}\) equal 1 if the tour travels directly from city \(i\) to city \(j\), and 0 otherwise. The objective is to maximize total travel distance:
Degree constraints
Every city must be departed from exactly once and arrived at exactly once:
These constraints ensure every city appears in the tour, but they still allow disconnected sub-tours, the same failure mode as the flow model.
Subtour elimination (Miller–Tucker–Zemlin, 1960)
The fix is to incldude Miller–Tucker–Zemlin (MTZ) subtour elimination constraints. Introduce an integer variable \(u_i\) representing the position of city \(i\) in the tour. Fix the starting city: \(u_1 = 1\). For all other cities, require:
The key idea is what happens when \(x_{ij} = 1\), i.e. when the tour actually travels from city \(i\) to \(j\). The right-hand side collapses to \(-1\), forcing \(u_j \geq u_i + 1\), so each step along the tour strictly increases the position counter. This makes it impossible for any subset of non-starting cities to form a closed loop. When \(x_{ij} = 0\), the constraint becomes \(u_i - u_j \leq n - 2\), which is always satisfied since positions are bounded in \([1, n]\).
The full model is an Mixed-Integer Linear Program (MILP) solved with Gurobi. With \(n = 24\) cities, the model has \(24^2 = 576\) binary variables, 24 integer position variables, and \(O(n^2)\) constraints. Gurobi finds the optimal solution in just a few seconds.
From cycle to path
The model finds a closed Hamiltonian cycle, meaning it ends where it began. A real racing calendar is an open path, so the cycle needs to be converted to the worst open itinerary. This was done by trying out all-possible combinations, just like the the MCF model, and computing the cycle distance minus the distance between the start and terminal cities.
Results
The solver returns a schedule that covers a total of 240,754 km, roughly six times the circumference of the Earth, or about 63% of the distance to the Moon. For comparison, F1's actual 2024 calendar covered approximately 80,000 km, so the worst-case schedule is about three times as long.
The pattern is exactly what you'd expect, with the solver relentlessly bounces between opposite sides of the planet. The São Paulo–Shanghai leg at 18,572 km crosses over the Atlantic ocean, the Mediterranean and Caspian seas, as well as all of Africa and Asia length-wise. Melbourne–Spa at 16,526 km traverses the Indian Ocean and Eurasia. The European cluster of Spa, Baku, Silverstone, sits in three consecutive positions in the middle of the table, simply because there is nowhere further to scatter them, every transoceanic combination has already been used. I like to think it's also partly due to the solver having a little mercy for the drivers and crews.
| Location | Distance to next |
|---|---|
| Imola | 9,589 km |
| Las Vegas | 9,494 km |
| Spielberg | 9,075 km |
| Austin | 9,317 km |
| Budapest | 10,273 km |
| São Paulo | 18,572 km |
| Shanghai | 9,806 km |
| Barcelona | 10,318 km |
| Suzuka | 9,869 km |
| Monaco | 10,421 km |
| Singapore | 10,258 km |
| Monza | 16,301 km |
| Melbourne | 16,526 km |
| Spa | 3,545 km |
| Baku | 4,030 km |
| Silverstone | 5,561 km |
| Yas Marina | 12,613 km |
| Miami | 12,318 km |
| Lusail | 14,109 km |
| Mexico City | 13,995 km |
| Sakhir | 10,266 km |
| Montreal | 9,961 km |
| Jeddah | 4,537 km |
| Zandvoort | — (end) |
| Total | 240,754 km |
Here is an interactive globe showing the optimal route. Each line connects consecutive destinations. Drag to rotate, scroll to zoom.
Loading graph…
Note that this model treats scheduling as a pure combinatorial problem, with no calendar constraints, no weather windows, and no logistical limits on how quickly equipment can move between continents. For instance, using this schedule would require organizing a race in the Netherlands in December, in freezing temperatures with a risk of snow. The real FIA scheduling problem is far more constrained.
In hindsight (2026 update)
With two additional years of knowledge, modeling, and mathematical maturity, I can now identify many areas for improvement.
First, in the MCF section, I mentioned that adding exponentially-many constraints that eliminate all possible subtours is impractical. It turns out that this method has a name, the Dantzig–Fulkerson–Johnson (DFJ) formulation, and can efficiently be solved via row-generation. Instead of adding all possible tours as constraints ahead of time, we first run a model with only degree constraints. Once we get a solution, we analyze it to find all subtours, and eliminate them by adding a constraint that specifically addresses those subtours. We then re-solve the problem with the new constraints, and repeat the procedure, until we have a solution with no tours. In practice, we recover a tour-free solution without having to add all \(O(n!)\)-many constraints
Second, instead of solving for all possible origin/destination pairs, one could simply add the selection directly into the model as a decision. We can add the variable \(o_i\), representing whether city \(i\) is the origin of the tour. Then, we add the big-\(M\) constraint of \(u_i \geq 2-o_i\), so when \(o_i = 0 \implies u_i \geq 2\) and \(o_i = 1 \implies u_i \geq 1-\) meaning only the chosen origin city can occupy the first position in the MTZ constraint. In the objective, we can thus add the term \[-\sum_{i \in V}\sum_{\substack{j \in V \\ j \neq i}} d_{ij}\, x_{ij} \,o_j\] which subtracts the distance corresponding to the incoming edge of the origin city. So the new objective becomes \[\sum_{i \in V}\sum_{\substack{j \in V \\ j \neq i}} d_{ij}\, x_{ij} \,(1-o_j)\]
I really enjoyed revisiting this quick little project. Going over the problem once again two years later and immediately being able to find solutions and improvements really goes to show how far I have come since then, both mathematically but also algorithmically.