247 lines
7.6 KiB
Markdown
247 lines
7.6 KiB
Markdown
# 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:
|
||
|
||
```c
|
||
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:
|
||
|
||
```c
|
||
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) and `n = 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:
|
||
|
||
```c
|
||
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:**
|
||
1. 0 → 1 → 2 → 0: distance = 1 + √2 + 1 = 3.41
|
||
2. 0 → 2 → 1 → 0: distance = 1 + √2 + 1 = 3.41
|
||
3. 1 → 0 → 2 → 1: distance = 1 + 1 + √2 = 3.41
|
||
4. 1 → 2 → 0 → 1: distance = √2 + 1 + 1 = 3.41
|
||
5. 2 → 0 → 1 → 2: distance = 1 + 1 + √2 = 3.41
|
||
6. 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 🏠
|
||
|
||
```c
|
||
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! 🎯
|
||
|
||
1. **This problem is NP-hard** - that's computer science speak for "really, really hard to solve quickly"
|
||
|
||
2. **Real delivery companies** use approximate algorithms that find "pretty good" solutions much faster than perfect ones
|
||
|
||
3. **With 11 cities** (the maximum our program handles), there are 39,916,800 possible routes!
|
||
|
||
4. **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:
|
||
1. **Read** all the city locations
|
||
2. **Generate** every possible visiting order
|
||
3. **Calculate** the total distance for each order
|
||
4. **Remember** the shortest distance found
|
||
5. **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! 🎉 |