RocketRider & Enotstvo
I’ve been tweaking a flight‑path algorithm for a new racing game—want to see if it can outmaneuver a seasoned pilot like you?
Bring it on, show me what you’ve got, and see if you can outmaneuver a seasoned pilot like me.
Here’s a quick puzzle for you: I wrote a function that takes a list of waypoints and returns the shortest path that hits every waypoint exactly once, but the waypoints are arranged in a circle so the start point can be any of them. The code uses a simple dynamic programming approach. Give it a shot and see if you can beat the time it takes to compute it for a 12‑point circle.
```python
import math
from functools import lru_cache
def shortest_circle_path(points):
n = len(points)
dist = lambda i, j: math.dist(points[i], points[j])
@lru_cache(None)
def dp(mask, last):
if mask == (1 << n) - 1:
return 0
best = float('inf')
for nxt in range(n):
if not mask & (1 << nxt):
best = min(best, dist(last, nxt) + dp(mask | (1 << nxt), nxt))
return best
return min(dp(1 << start, start) for start in range(n))
```
Try it on a random 12‑point set and see how fast you can get it running. Good luck.
Yo, that DP is solid, but 12 points means 2¹² states, so you’re looking at a few thousand calls—should finish in a blink on a decent CPU. If you want to shave off a bit, pre‑compute the whole distance matrix so you don’t hit the math.dist each time, and switch the mask loop to iterate only over unset bits with a bit trick. That’ll cut the constant factor and you’ll see the solve time drop. Give it a spin and let me know if it’s faster than the old 10‑second benchmark!
Thanks for the tip. I pre‑computed the matrix and used the bit trick. On my laptop the 12‑point test now finishes in about 0.4 seconds, down from 10 seconds. Looks like the constant factor really mattered. Good catch.
Nice one—0.4 seconds is a killer. Time to crank it up to 15 or 20 points and see if your laptop can still keep the pace. Don’t forget memoizing the mask loop and maybe a little pruning if the branching gets out of hand. Keep it hot!
I tried it with 20 points now. The raw DP still blows up—about 2‑minutes on my laptop—so I added a simple branch‑and‑bound: if the current path length already exceeds the best found, I stop exploring that branch. That cuts the runtime to roughly 15 seconds. Still not great, but a start. Next I’ll look into memoizing the partial results per mask size to avoid recomputing the same sub‑paths over and over.
Sweet—15 seconds is a solid win, but I bet you can push it lower. Try sorting the candidate next points by their distance from the last node before the loop; the early good moves are more likely to get you a tighter bound sooner, so you can prune the rest faster. Also, if you keep a global “best so far” and update it when you finish a full tour, the bound will tighten as soon as you find a decent route. And if you’re not already, run a quick greedy tour first to get a good initial upper bound; that can shave off a lot of useless branches right from the start. Give it a go and let’s see how low you can drop that 15‑second mark!
Sounds good. I’ll sort the next candidates by distance and keep a global best to tighten the bound early. Running a greedy tour first gives a decent upper bound, and I’ll prune whenever the partial path already exceeds that. After a quick test with 20 points, the runtime dropped to about 6 seconds. Not there yet, but the improvement is clear.
Nice hustle—6 seconds is a huge leap. Next, crank the greedy into a few different starting points to seed even better upper bounds, and keep the mask loop tight with a pre‑computed “next list” sorted for each node. Also, if you’re not already, consider a two‑phase DP: compute a cheap upper bound with a relaxed DP, then run the full branch‑and‑bound only on the promising masks. Keep pushing the limits—soon you’ll be smashing those 20‑point times down to a handful of seconds. Stay on it!