7.6 KiB
The Traveling Salesman Problem (TSP) - Simple Explanation
What is the Traveling Salesman Problem? 🗺️
Imagine you're a delivery person who needs to visit several houses in your neighborhood and then return home. You want to find the shortest possible route that visits every house exactly once and brings you back to where you started.
That's exactly what the Traveling Salesman Problem is about!
Real-World Example
Let's say you need to deliver pizza to 4 houses:
- Your home: (0, 0)
- House A: (1, 0)
- House B: (1, 1)
- House C: (0, 1)
C ---- B
| |
| |
Home - A
You could go in many different orders:
- Home → A → B → C → Home
- Home → A → C → B → Home
- Home → B → A → C → Home
- ... and many more!
But which path is the shortest? That's what our algorithm finds out!
How Our Algorithm Works 🔍
Our solution uses a "brute force" approach, which means: "Let's try EVERY possible path and pick the shortest one!"
It's like trying on every shirt in your closet to find the one that fits best - not the fastest way, but it guarantees you'll find the perfect answer!
Step 1: Calculate Distance Between Two Points
First, we need to know how far apart two places are:
static float distance(t_city a, t_city b)
{
float dx = b.x - a.x; // How far left/right?
float dy = b.y - a.y; // How far up/down?
return (sqrtf(dx * dx + dy * dy)); // Pythagorean theorem!
}
What's happening here?
dx= horizontal distance (like counting steps left or right)dy= vertical distance (like counting steps up or down)sqrtf(dx*dx + dy*dy)= the straight-line distance (like a bird flying)
Example: From Home (0,0) to House A (1,0):
- dx = 1 - 0 = 1
- dy = 0 - 0 = 0
- distance = √(1² + 0²) = √1 = 1.0
Step 2: Calculate Total Path Length
Now we add up all the distances in a complete round trip:
static float path_length(t_city *cities, int *route, int n)
{
float total = 0;
int i = 0;
while (i < n)
{
// Add distance from current city to next city
total += distance(cities[route[i]], cities[route[(i + 1) % n]]);
i++;
}
return (total);
}
What's that weird % n thing?
It's like a clock! When you get to hour 12, the next hour is 1, not 13.
- When
i = 3(last city) andn = 4(total cities) (i + 1) % n = (3 + 1) % 4 = 4 % 4 = 0- So we go from the last city back to the first city (completing the circle!)
Step 3: Try All Possible Routes
This is where the magic happens! We generate every possible order of visiting the cities:
static void solve(t_city *cities, int *route, int pos, int n, float *best)
{
float current;
int i, temp;
// If we've arranged all cities, check this route
if (pos == n)
{
current = path_length(cities, route, n);
if (current < *best)
*best = current; // Found a better route!
return;
}
// Try putting each remaining city in the current position
i = pos;
while (i < n)
{
// Swap cities (like switching the order of your visits)
temp = route[pos];
route[pos] = route[i];
route[i] = temp;
// Try all arrangements with this city in this position
solve(cities, route, pos + 1, n, best);
// Swap back (undo the change)
temp = route[pos];
route[pos] = route[i];
route[i] = temp;
i++;
}
}
Think of it like this:
- Position 0: "Which city should I visit first?"
- Position 1: "Which city should I visit second?"
- Position 2: "Which city should I visit third?"
- And so on...
For each position, we try putting each remaining city there and see what happens!
Complete Example Walkthrough 🚶♂️
Let's trace through a simple 3-city example:
- City 0: (0, 0)
- City 1: (1, 0)
- City 2: (0, 1)
2
|
|
0 --- 1
All possible routes:
- 0 → 1 → 2 → 0: distance = 1 + √2 + 1 = 3.41
- 0 → 2 → 1 → 0: distance = 1 + √2 + 1 = 3.41
- 1 → 0 → 2 → 1: distance = 1 + 1 + √2 = 3.41
- 1 → 2 → 0 → 1: distance = √2 + 1 + 1 = 3.41
- 2 → 0 → 1 → 2: distance = 1 + 1 + √2 = 3.41
- 2 → 1 → 0 → 2: distance = √2 + 1 + 1 = 3.41
Result: All routes have the same length! (This makes sense - it's a triangle, so any direction around it is the same distance.)
The Main Program 🏠
int main(void)
{
t_city cities[11]; // Space for up to 11 cities
int route[11]; // The order we'll visit cities
int n = 0; // How many cities we actually have
float best = 999999.0f; // Start with a really big number
// Read city coordinates from input
while (n < 11 && fscanf(stdin, "%f, %f", &cities[n].x, &cities[n].y) == 2)
{
route[n] = n; // Initially: visit cities in order 0,1,2,3...
n++;
}
if (n < 2)
return (1); // Need at least 2 cities for a trip!
solve(cities, route, 0, n, &best); // Find the best route
fprintf(stdout, "%.2f\n", best); // Print the shortest distance
return (0);
}
Why This Works (But Is Slow) ⏰
The Good:
- ✅ Always finds the perfect answer - we check every possibility!
- ✅ Simple to understand - no complex tricks or shortcuts
- ✅ Works for any arrangement of cities
The Not-So-Good:
- ❌ Gets very slow with more cities
- For 3 cities: 6 routes to check
- For 4 cities: 24 routes to check
- For 10 cities: 3,628,800 routes to check! 😱
Why it gets so big:
- 1st city: 10 choices
- 2nd city: 9 choices (can't repeat)
- 3rd city: 8 choices
- ...
- Total: 10 × 9 × 8 × 7 × 6 × 5 × 4 × 3 × 2 × 1 = 3,628,800
This is called "factorial growth" - it explodes very quickly!
Key Programming Concepts Used 💻
1. Recursion
The solve() function calls itself! It's like Russian nesting dolls - each call handles one position, then asks a smaller version of itself to handle the rest.
2. Backtracking
We try something (swap cities), explore all possibilities, then undo it (swap back). Like trying different paths in a maze and backing up when we hit a dead end.
3. Permutations
We generate every possible ordering of the cities. It's like having cards numbered 1,2,3 and arranging them in every possible order: 123, 132, 213, 231, 312, 321.
4. Global Optimization
We keep track of the best solution found so far and update it whenever we find something better.
Fun Facts! 🎯
-
This problem is NP-hard - that's computer science speak for "really, really hard to solve quickly"
-
Real delivery companies use approximate algorithms that find "pretty good" solutions much faster than perfect ones
-
With 11 cities (the maximum our program handles), there are 39,916,800 possible routes!
-
The problem has applications in:
- GPS navigation systems
- Circuit board manufacturing
- DNA sequencing
- Planning efficient tours for bands or sports teams
Summary 📝
Our TSP algorithm is like a very thorough friend who insists on checking every possible pizza delivery route before deciding which one is shortest. It's not the fastest approach, but it guarantees the perfect answer!
The main steps are:
- Read all the city locations
- Generate every possible visiting order
- Calculate the total distance for each order
- Remember the shortest distance found
- Print the answer
Even though it's not the most efficient algorithm for large problems, it's perfect for learning because it's easy to understand and always gives the correct answer! 🎉