added tsp
This commit is contained in:
commit
2dfffb7ab5
26
tsp/Makefile
Normal file
26
tsp/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
NAME = tsp
|
||||
|
||||
SRCS = tsp.c
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
MATH_FLAGS = -lm
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
$(NAME): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(OBJS) -o $(NAME) $(MATH_FLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
|
||||
fclean: clean
|
||||
rm -f $(NAME)
|
||||
|
||||
re: fclean all
|
||||
|
||||
.PHONY: all clean fclean re
|
||||
247
tsp/TSP_Algorithm_Explained.md
Normal file
247
tsp/TSP_Algorithm_Explained.md
Normal file
@ -0,0 +1,247 @@
|
||||
# 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! 🎉
|
||||
8
tsp/square.txt
Normal file
8
tsp/square.txt
Normal file
@ -0,0 +1,8 @@
|
||||
0, 0
|
||||
1, 0
|
||||
2, 0
|
||||
0, 1
|
||||
1, 1
|
||||
2, 1
|
||||
5, 2
|
||||
2, 2
|
||||
64
tsp/subject.txt
Normal file
64
tsp/subject.txt
Normal file
@ -0,0 +1,64 @@
|
||||
Assignment name: tsp
|
||||
Expected files: *.c *.h
|
||||
Allowed functions: write, sqrtf, getline, fseek, fscanf, ferror, feof,
|
||||
fabsf, memcpy, fprintf, fclose, malloc, calloc, realloc, free, fopen,
|
||||
errno, stderr, stdin, stdout
|
||||
-------------------------------------------------------
|
||||
|
||||
The first publication referring to this problem as the "traveling salesman
|
||||
problem" is found in the 1949 RAND Corporation report by Julia Robinson,
|
||||
"On the Hamiltonian game (a traveling salesman problem)."
|
||||
|
||||
Here is how she defines the problem:
|
||||
|
||||
"The purpose of this note is to give a method for solving a problem related
|
||||
to the traveling salesman problem. It seems worthwhile to give a description
|
||||
of the original problem. One formulation is to find the shortest route for a
|
||||
salesman starting from Washington, visiting all the state capitals and then
|
||||
returning to Washington.
|
||||
|
||||
More generally, to find the shortest CLOSED CURVE containing n given points
|
||||
in the plane."
|
||||
|
||||
for example with the following set of cities:
|
||||
0, 0
|
||||
1, 0
|
||||
2, 0
|
||||
0, 1
|
||||
1, 1
|
||||
2, 1
|
||||
1, 2
|
||||
2, 2
|
||||
which can be presented as follows:
|
||||
+ + +
|
||||
+ + +
|
||||
+ +
|
||||
the shortest path is:
|
||||
_____
|
||||
|__ |
|
||||
|__|
|
||||
|
||||
so you should print the length of this path that is:
|
||||
8.00
|
||||
|
||||
Write a program that will read a set of city coordinates in the form
|
||||
'%f, %f\n' from the standard input and will print the length of the shortest
|
||||
possible path containing all these cities under the form '%.2f'.
|
||||
|
||||
Your program will not be tested with more than 11 cities.
|
||||
|
||||
You will find in this directory a file tsp.c containing all the boring parts of
|
||||
this exercise and example files to help you test your program.
|
||||
|
||||
hint: in order to use sqrtf, add -lm at the end of your compilation command.
|
||||
|
||||
For example this should work:
|
||||
$> cat square.txt
|
||||
1, 1
|
||||
0, 1
|
||||
1, 0
|
||||
0, 0
|
||||
$> ./tsp < square.txt | cat -e
|
||||
4.00$
|
||||
|
||||
Hint : in order to use sqrtf , add -lm at the end of your compilation command
|
||||
66
tsp/tsp.c
Normal file
66
tsp/tsp.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "tsp.h"
|
||||
|
||||
static float distance(t_city a, t_city b)
|
||||
{
|
||||
float dx = b.x - a.x;
|
||||
float dy = b.y - a.y;
|
||||
return (sqrtf(dx * dx + dy * dy));
|
||||
}
|
||||
|
||||
static float path_length(t_city *cities, int *route, int n)
|
||||
{
|
||||
float total = 0;
|
||||
int i = 0;
|
||||
|
||||
while (i < n)
|
||||
{
|
||||
total += distance(cities[route[i]], cities[route[(i + 1) % n]]);
|
||||
i++;
|
||||
}
|
||||
return (total);
|
||||
}
|
||||
|
||||
static void solve(t_city *cities, int *route, int pos, int n, float *best)
|
||||
{
|
||||
float current;
|
||||
int i, temp;
|
||||
|
||||
if (pos == n)
|
||||
{
|
||||
current = path_length(cities, route, n);
|
||||
if (current < *best)
|
||||
*best = current;
|
||||
return;
|
||||
}
|
||||
i = pos;
|
||||
while (i < n)
|
||||
{
|
||||
temp = route[pos];
|
||||
route[pos] = route[i];
|
||||
route[i] = temp;
|
||||
solve(cities, route, pos + 1, n, best);
|
||||
temp = route[pos];
|
||||
route[pos] = route[i];
|
||||
route[i] = temp;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
t_city cities[11];
|
||||
int route[11];
|
||||
int n = 0;
|
||||
float best = 999999.0f;
|
||||
|
||||
while (n < 11 && fscanf(stdin, "%f, %f", &cities[n].x, &cities[n].y) == 2)
|
||||
{
|
||||
route[n] = n;
|
||||
n++;
|
||||
}
|
||||
if (n < 2)
|
||||
return (1);
|
||||
solve(cities, route, 0, n, &best);
|
||||
fprintf(stdout, "%.2f\n", best);
|
||||
return (0);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user