Edited README's, added broken_gnl exercise, LICENSE and main README

This commit is contained in:
Rui Ribeiro 2025-10-05 17:10:55 +01:00
parent 4b8a2c7481
commit f1b9d38007
12 changed files with 358 additions and 1336 deletions

72
LICENSE Normal file
View File

@ -0,0 +1,72 @@
# LICENSE
## Academic Exercise Solutions Repository
This repository contains academic exercise solutions developed as part of the École 42 curriculum.
### Repository Contents
- **Exercise Subjects**: Intellectual property of École 42, included here only for educational context and reference.
- **Solutions & Implementations**: Original work by the repository author, licensed under terms below.
---
## LICENSE TERMS
### For the Solutions & Implementations (Original Code):
This original code is licensed under the following terms, intended for **non-commercial use only**.
**You are free to:**
- Use, study, and modify the code for personal, academic, or educational purposes.
- Share the code and derivative works as long as they remain non-commercial.
- Distribute your modifications under the same non-commercial license.
**Conditions:**
- Attribution must be given to the original author (Rui Ribeiro).
- This code and any derivatives must not be used for commercial purposes.
- The license must accompany any distribution.
- Any changes must be clearly documented.
- Source code must remain openly available under these same terms.
**Prohibited:**
- Using, distributing, or incorporating the code in any commercial, for-profit, or revenue-generating activity,
unless explicit written permission is granted by the author.
- Creating proprietary or closed-source derivatives.
**Contact for commercial licensing or permissions:**
contacto [at] ruiribeiro [dot] me
---
### For the Exercise Subjects:
**Copyright Notice:**
The exercise subjects, problem statements, and related materials are the exclusive intellectual property of École 42.
They are included solely for **educational reference and context** within this repository.
**Permitted Use:**
You may view and study these materials exclusively in conjunction with this repository for non-commercial academic purposes only.
**Contact for École 42 Representatives:**
If you represent École 42 and have any concerns, requests for removal, or other issues regarding the inclusion of the exercise subjects, please contact the repository owner at:
contacto [at] ruiribeiro [dot] me
---
## COPYRIGHT & ATTRIBUTION
**Original Solutions & Implementations**:
Copyright (c) 2025 Rui Ribeiro
**Exercise Subjects:**
Copyright École 42
**Repository maintained by:** Rui Ribeiro
**Contact:** contacto [at] ruiribeiro [dot] me
**Date:** October 2025
---
## DISCLAIMER
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE.

125
README.md Normal file
View File

@ -0,0 +1,125 @@
# Exam Rank 03 — 42 School: Exercise Solutions
This repository contains solutions to the Exam Rank 03 exercises from the 42
School curriculum. The content is organized by exercise level and includes the
exercise subjects (for reference) together with example implementations and
build scripts where applicable.
This README provides an overview of the repository, how to build and run the
exercises, a short description of each exercise, and testing notes.
## Repository layout
- `level-1/`
- `broken_gnl/` — a variant of the "get_next_line" assignment (broken/intentional-bug version and subject)
- `filter/` — program that replaces occurrences of a substring with asterisks
- `scanf/` — partial implementation of `ft_scanf`
- `level-2/`
- `n_queens/` — N-Queens solutions with Makefile and subject
- `permutations/` — generate all permutations of a string in alphabetical order
- `powerset/` — find subsets that sum to a target value
- `tsp/` — brute-force traveling salesman solver (small n)
- `rip/` — parentheses balancing and minimal removal solutions
Each exercise directory typically contains:
- `subject.txt` or `README.md` — the exercise statement provided for reference
- `*.c`, `*.h` — implementation and headers
- `Makefile` — build helper (for many level-2 exercises)
## Purpose and license
The exercise subjects are the property of 42 School and are included for
educational reference. Implementations contained in this repository are the
original work of the repository author and are provided for non-commercial
educational use only (see `LICENSE` for full terms and contact information).
## Building
General notes:
- The projects are standard C programs and use `gcc`.
- Several level-2 directories include a `Makefile` with standard targets:
- `make` / `make all` — compile the program
- `make clean` — remove object files
- `make fclean` — remove object files and executable
- `make re` — rebuild from scratch
- `make test` — run example tests (where provided)
Examples (run from repository root):
Change into an exercise directory and build:
cd level-2/n_queens
make
For `tsp` the Makefile links against libm, so the `-lm` flag is used automatically.
## Running the exercises (summary)
Below are concise descriptions and usage examples for each exercise. For full
details refer to the exercise `subject.txt` or the directory README.
- broken_gnl (level-1/broken_gnl)
- Purpose: an implementation of a `get_next_line`-like function. The
directory includes a subject and a sample (intentionally flawed) solution.
- filter (level-1/filter)
- Purpose: read stdin and replace every occurrence of the given pattern with
a sequence of asterisks of equal length.
- Usage: `./filter <pattern>`
- Example: `echo "abcabc" | ./filter abc` outputs `*** ***` (without spaces)
- scanf (level-1/scanf)
- Purpose: partial reimplementation of `scanf` supporting `%s`, `%d` and `%c`.
- The directory contains a working `ft_scanf.c` and helper subject file.
- n_queens (level-2/n_queens)
- Purpose: print all valid placements of N queens on an N×N board.
- Usage: `./n_queens N`
- Output: lines with N integers representing row positions for each column.
- permutations (level-2/permutations)
- Purpose: print all permutations of the input string in alphabetical order.
- Usage: `./permutations <string>`
- powerset (level-2/powerset)
- Purpose: list all subsets of the provided set whose elements sum to the
target integer (first argument).
- Usage: `./powerset <target> <list of distinct integers>`
- tsp (level-2/tsp)
- Purpose: brute-force shortest closed path visiting all given points (n ≤ 11).
- Usage: `./tsp < input.txt` where input has lines like `x, y` (floating points).
- Output: a single floating number formatted to two decimals (e.g. `8.00`).
- rip (level-2/rip)
- Purpose: remove the minimum number of parentheses (replace by spaces) to
make input strings balanced and print all distinct minimal solutions.
- Usage: `./rip "( )..."`
## Testing notes
- Many directories include example `Makefile` targets named `test` that run the
compiled binary with sample inputs from the exercise statements. Use those
targets to verify behavior quickly.
- For exercises that read from stdin, you can pipe data via `echo` or use file
redirection: `./tsp < level-2/tsp/square.txt`.
## Quality and limitations
- These are educational implementations. Some directories include intentionally
broken code (for debugging practice) or partial templates intended to be
completed.
- The programs follow the constraints given in each subject (allowed
functions, expected behavior on edge cases, and error handling).
## Contributing and contact
This repository is a personal collection of exercise solutions. Contributions are
welcome as long as they follow the repository license and respect the original
exercise authorship. For questions, corrections or requests regarding licensing
or removal of subject material, contact the repository owner (see `LICENSE`).
---
Last updated: October 2025

View File

@ -0,0 +1,97 @@
#include "broken_gnl.h"
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
char *ft_strchr(char *s, int c)
{
int i = 0;
while (s[i] && s[i] != c)
i++;
if (s[i] == c)
return (s + i);
else
return (NULL);
}
void *ft_memcpy(void *dest, const void *src, size_t n)
{
size_t i = 0;
while (i < n)
{
((char *)dest)[i] = ((char *)src)[i];
i++;
}
return (dest);
}
size_t ft_strlen(char *s)
{
if (!s)
return 0;
size_t ret = 0;
while (*s)
{
s++;
ret++;
}
return (ret);
}
int str_append_mem(char **s1, char *s2, size_t size2)
{
size_t size1 = ft_strlen(*s1);
char *tmp = malloc(size2 + size1 + 1);
if (!tmp)
return (0);
if (*s1)
ft_memcpy(tmp, *s1, size1);
ft_memcpy(tmp + size1, s2, size2);
tmp [size1 + size2] = 0;
free(*s1);
*s1 = tmp;
return (1);
}
int str_append_str(char **s1, char *s2)
{
return (str_append_mem(s1, s2, ft_strlen(s2)));
}
void *ft_memmove(void *dest, const void *src, size_t n)
{
if (dest == src)
return (dest);
return (ft_memcpy(dest, src, n));
}
char *get_next_line(int fd)
{
static char b[BUFFER_SIZE + 1] = "";
char *ret = NULL;
char *tmp = ft_strchr(b, '\n');
while (!tmp)
{
if (!str_append_str(&ret, b))
return (NULL);
int read_ret = read(fd, b, BUFFER_SIZE);
if (read_ret == -1 || read_ret == 0)
{
free(ret);
return (NULL);
}
b[read_ret] = 0;
tmp = ft_strchr(b, '\n');
}
if (!str_append_mem(&ret, b, tmp - b + 1))
{
free(ret);
return (NULL);
}
ft_memmove(b, tmp + 1, ft_strlen(tmp + 1) + 1);
return (ret);
}

View File

@ -1,24 +1,4 @@
/*
* EJERCICIO: FILTER
*
* DESCRIPCIÓN:
* Leer de stdin y escribir a stdout, pero reemplazando todas las ocurrencias
* de una cadena dada por asteriscos (*) de la misma longitud.
*
* CONCEPTOS CLAVE:
* 1. LECTURA DINÁMICA: read() con buffer variable
* 2. BÚSQUEDA DE PATRONES: strstr() o memmem()
* 3. GESTIÓN DE MEMORIA: realloc() para buffer dinámico
* 4. MANEJO DE ERRORES: perror() para errores de sistema
*
* ALGORITMO:
* 1. Leer todo el contenido de stdin en un buffer dinámico
* 2. Buscar todas las ocurrencias del patrón
* 3. Reemplazar cada ocurrencia con asteriscos
* 4. Escribir el resultado a stdout
*/
#define _GNU_SOURCE // Para memmem()
#define _GNU_SOURCE
#ifndef BUFFER_SIZE
# define BUFFER_SIZE 42
#endif
@ -29,42 +9,30 @@
#include <errno.h>
#include <string.h>
// Función para encontrar y reemplazar todas las ocurrencias
void ft_filter(char *buffer, const char *target)
{
int i = 0;
int target_len = strlen(target);
int j, k;
/*
* ALGORITMO DE BÚSQUEDA Y REEMPLAZO:
* - Recorrer el buffer carácter por carácter
* - En cada posición, verificar si coincide con el patrón
* - Si coincide, escribir asteriscos y saltar la longitud del patrón
* - Si no coincide, escribir el carácter original
*/
while (buffer[i])
{
j = 0;
// Verificar si hay coincidencia desde la posición actual
while (target[j] && (buffer[i + j] == target[j]))
j++;
if (j == target_len) // Coincidencia completa encontrada
if (j == target_len)
{
// Escribir asteriscos en lugar del patrón
k = 0;
while (k < target_len)
{
write(1, "*", 1);
k++;
}
i += target_len; // Saltar el patrón completo
i += target_len;
}
else
{
// No hay coincidencia, escribir carácter original
write(1, &buffer[i], 1);
i++;
}
@ -73,30 +41,18 @@ void ft_filter(char *buffer, const char *target)
int main(int argc, char **argv)
{
/*
* VALIDACIÓN DE ARGUMENTOS:
* - Debe haber exactamente 1 argumento
* - El argumento no puede estar vacío
*/
if (argc != 2 || argv[1][0] == '\0')
return 1;
/*
* LECTURA DINÁMICA DE STDIN:
* - Usar buffer temporal para leer chunks
* - Usar realloc() para expandir el buffer principal
* - Mantener seguimiento del total leído
*/
char temp[BUFFER_SIZE];
char *result = NULL;
char *buffer;
int total_read = 0;
ssize_t bytes;
// Leer de stdin hasta EOF
while ((bytes = read(0, temp, BUFFER_SIZE)) > 0)
{
// Expandir el buffer principal para acomodar los nuevos datos
buffer = realloc(result, total_read + bytes + 1);
if (!buffer)
{
@ -107,13 +63,11 @@ int main(int argc, char **argv)
result = buffer;
// Copiar los nuevos datos al buffer principal
memmove(result + total_read, temp, bytes);
total_read += bytes;
result[total_read] = '\0'; // Asegurar terminación
result[total_read] = '\0';
}
// Verificar errores de lectura
if (bytes < 0)
{
perror("read");
@ -121,38 +75,10 @@ int main(int argc, char **argv)
return 1;
}
// Si no se leyó nada, salir sin error
if (!result)
return 0;
// Procesar el buffer y aplicar el filtro
ft_filter(result, argv[1]);
// Liberar memoria
free(result);
return 0;
}
/*
* PUNTOS CLAVE PARA EL EXAMEN:
*
* 1. GESTIÓN DE MEMORIA:
* - Siempre verificar el retorno de malloc/realloc
* - Liberar memoria en caso de error
* - Usar memmove() en lugar de memcpy() para solapamientos
*
* 2. MANEJO DE ERRORES:
* - Usar perror() para errores de sistema
* - Retornar códigos de error apropiados
* - Validar argumentos antes de usarlos
*
* 3. LECTURA DINÁMICA:
* - El buffer puede llenarse con cualquier cantidad de datos
* - Usar realloc() para expandir según sea necesario
* - Mantener un terminador nulo válido
*
* 4. ALGORITMO EFICIENTE:
* - Búsqueda simple carácter por carácter
* - Evitar usar funciones no permitidas
* - Escribir directamente a stdout sin almacenar el resultado
*/

View File

@ -1,323 +0,0 @@
/*
* EJERCICIO: FT_SCANF
*
* DESCRIPCIÓN:
* Implementar una versión simplificada de scanf que maneje solo %s, %d y %c.
*
* CONCEPTOS CLAVE:
* 1. ARGUMENTOS VARIABLES: va_list, va_start, va_arg, va_end
* 2. PARSING DE FORMATO: Analizar string de formato carácter por carácter
* 3. LECTURA DE ARCHIVO: fgetc(), ungetc() para control de flujo
* 4. CONVERSIONES: Convertir strings a números, manejar espacios en blanco
*
* FORMATO SOPORTADO:
* - %s: string (hasta el primer espacio en blanco)
* - %d: entero decimal (con signo opcional)
* - %c: un solo carácter
*/
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
// Función para saltar espacios en blanco en el stream
int match_space(FILE *f)
{
/*
* MANEJO DE ESPACIOS EN BLANCO:
* - Leer caracteres mientras sean espacios
* - Devolver el primer carácter no-espacio al stream
* - Retornar -1 en caso de error
*/
int ch = fgetc(f);
if (ch == EOF && ferror(f))
return -1;
while (ch != EOF)
{
if (!isspace(ch))
{
ungetc(ch, f); // Devolver carácter no-espacio
break;
}
ch = fgetc(f);
}
if (ferror(f))
return -1;
return 1;
}
// Función para verificar un carácter específico
int match_char(FILE *f, char c)
{
/*
* COINCIDENCIA DE CARACTERES LITERALES:
* - Leer un carácter del stream
* - Verificar si coincide con el esperado
* - Devolver al stream si no coincide
*/
int ch = fgetc(f);
if (ch == c)
return 1;
if (ch != EOF)
ungetc(ch, f);
return -1;
}
// Función para leer un carácter (%c)
int scan_char(FILE *f, va_list ap)
{
/*
* CONVERSIÓN %c:
* - Leer exactamente un carácter
* - No saltar espacios en blanco
* - Almacenar en el puntero proporcionado
*/
int ch = fgetc(f);
char *cp = va_arg(ap, char *);
if (ch == EOF)
return -1;
*cp = (char)ch;
return 1;
}
// Función para leer un entero (%d)
int scan_int(FILE *f, va_list ap)
{
/*
* CONVERSIÓN %d:
* - Saltar espacios en blanco iniciales
* - Leer signo opcional (+/-)
* - Leer dígitos y construir el número
* - Devolver último carácter no-dígito al stream
*/
int sign = 1;
int value = 0;
int ch = fgetc(f);
int *ip = va_arg(ap, int *);
int count = 0;
if (ch == EOF)
return -1;
// Saltar espacios en blanco
while (isspace(ch))
ch = fgetc(f);
// Manejar signo
if (ch == '-')
{
sign = -1;
ch = fgetc(f);
}
else if (ch == '+')
{
ch = fgetc(f);
}
// Verificar que el primer carácter sea un dígito
if (!isdigit(ch))
{
ungetc(ch, f);
return -1;
}
// Leer dígitos y construir el número
while (isdigit(ch))
{
value = value * 10 + (ch - '0');
count++;
ch = fgetc(f);
}
// Devolver último carácter no-dígito
if (ch != EOF)
ungetc(ch, f);
if (count == 0)
return -1;
*ip = value * sign;
return 1;
}
// Función para leer un string (%s)
int scan_string(FILE *f, va_list ap)
{
/*
* CONVERSIÓN %s:
* - Saltar espacios en blanco iniciales
* - Leer caracteres hasta encontrar espacio en blanco
* - Terminar el string con '\0'
* - Devolver último carácter de espacio al stream
*/
int ch = fgetc(f);
char *sp = va_arg(ap, char *);
int i = 0;
// Saltar espacios en blanco iniciales
while (ch != EOF && isspace(ch))
ch = fgetc(f);
if (ch == EOF)
return -1;
// Leer caracteres hasta espacio en blanco
do
{
sp[i] = ch;
i++;
ch = fgetc(f);
} while (ch != EOF && !isspace(ch));
sp[i] = '\0'; // Terminar string
// Devolver carácter de espacio al stream
if (ch != EOF)
ungetc(ch, f);
if (i == 0)
return -1;
return 1;
}
// Función para manejar conversiones de formato
int match_conv(FILE *f, const char **format, va_list ap)
{
/*
* DISPATCHER DE CONVERSIONES:
* - Analizar el carácter de conversión
* - Llamar a la función apropiada
* - Manejar espacios para %d y %s automáticamente
*/
switch (**format)
{
case 'c':
return scan_char(f, ap);
case 'd':
match_space(f); // %d salta espacios automáticamente
return scan_int(f, ap);
case 's':
match_space(f); // %s salta espacios automáticamente
return scan_string(f, ap);
case '\0':
return -1;
default:
return -1; // Conversión no soportada
}
}
// Función principal de scanf
int ft_vfscanf(FILE *f, const char *format, va_list ap)
{
/*
* LÓGICA PRINCIPAL DE SCANF:
* - Analizar string de formato carácter por carácter
* - Manejar caracteres literales y conversiones (%)
* - Contar conversiones exitosas
* - Parar en el primer error
*/
int nconv = 0; // Número de conversiones exitosas
// Verificar que hay datos disponibles
int c = fgetc(f);
if (c == EOF)
return EOF;
ungetc(c, f);
while (*format)
{
if (*format == '%')
{
// Conversión encontrada
format++;
if (match_conv(f, &format, ap) != 1)
break; // Error en conversión
else
nconv++; // Conversión exitosa
}
else if (isspace(*format))
{
// Espacio en blanco en formato: saltar espacios en input
if (match_space(f) == -1)
break;
}
else
{
// Carácter literal: debe coincidir exactamente
if (match_char(f, *format) != 1)
break;
}
format++;
}
// Verificar errores de archivo
if (ferror(f))
return EOF;
return nconv; // Retornar número de conversiones exitosas
}
// Función wrapper para scanf estándar
int ft_scanf(const char *format, ...)
{
/*
* WRAPPER PARA ARGUMENTOS VARIABLES:
* - Inicializar va_list
* - Llamar a la función principal con stdin
* - Limpiar va_list
*/
va_list ap;
va_start(ap, format);
int ret = ft_vfscanf(stdin, format, ap);
va_end(ap);
return ret;
}
/*
* EJEMPLO DE USO:
*
* int main(void)
* {
* int x;
* char str[100];
* char c;
*
* // Leer: número, espacio, string, espacio, carácter
* int converted = ft_scanf("%d %s %c", &x, str, &c);
*
* printf("Convertidos: %d\n", converted);
* printf("Número: %d, String: %s, Carácter: %c\n", x, str, c);
*
* return 0;
* }
*/
/*
* PUNTOS CLAVE PARA EL EXAMEN:
*
* 1. ARGUMENTOS VARIABLES:
* - va_start(ap, last_param) para inicializar
* - va_arg(ap, type) para obtener siguiente argumento
* - va_end(ap) para limpiar
*
* 2. CONTROL DE FLUJO DE ARCHIVO:
* - fgetc() para leer carácter
* - ungetc() para devolver carácter al stream
* - ferror() para verificar errores
*
* 3. MANEJO DE ESPACIOS:
* - %c NO salta espacios en blanco
* - %d y %s SÍ saltan espacios en blanco
* - Espacios en formato coinciden con cualquier whitespace
*
* 4. VALOR DE RETORNO:
* - Número de conversiones exitosas
* - EOF si error de archivo o EOF antes de conversiones
* - Parar en primera conversión fallida
*/

View File

@ -2,67 +2,47 @@
#include <stdarg.h>
#include <ctype.h>
/*
* Consome todos os caracteres de espaço em branco consecutivos do stream.
* Retorna 1 em sucesso, -1 em caso de erro de leitura.
*/
int match_space(FILE *f)
{
int ch;
// Lê caracteres enquanto não for o fim do ficheiro e forem espaços
while ((ch = fgetc(f)) != EOF && isspace(ch))
{
// O corpo do loop está vazio de propósito, apenas consome os caracteres
}
{}
// Se o loop parou por um caractere que não é espaço, coloca-o de volta
if (ch != EOF)
ungetc(ch, f);
// Verifica se ocorreu um erro de leitura durante as operações
if (ferror(f))
return -1;
return 1;
}
/*
* Tenta corresponder a um caractere específico 'c'.
* era simples e eficiente, não necessitou de alterações.
*/
int match_char(FILE *f, char c)
{
int ch = fgetc(f);
if (ch == c)
return 1; // Sucesso, caractere corresponde
return 1;
// Se não correspondeu, e não é o fim do ficheiro, devolve o caractere
if (ch != EOF)
ungetc(ch, f);
return -1; // Falha na correspondência
return -1;
}
/*
* um único caractere do stream e armazena-o.
* era simples e direto, não necessitou de alterações.
*/
int scan_char(FILE *f, va_list ap)
{
int ch = fgetc(f);
char *cp = va_arg(ap, char *);
if (ch == EOF)
return -1; // Falha se chegar ao fim do ficheiro
return -1;
*cp = (char)ch;
return 1;
}
/*
* um inteiro do stream, ignorando espaços iniciais e tratando o sinal.
*/
int scan_int(FILE *f, va_list ap)
{
int *ip = va_arg(ap, int *);

View File

@ -1,19 +1,19 @@
# N-Queens Problem - Simple Explanation 👑
# N-Queens
## What is the N-Queens Problem? 🤔
## What is the N-Queens Problem?
Imagine you have a chessboard and some queens (the most powerful pieces in chess). The N-Queens problem is like a puzzle where you need to place N queens on an N×N chessboard so that **none of them can attack each other**.
### What's a Queen in Chess?
### What's a Queen in Chess?
A queen is the strongest piece in chess. She can move:
- **Horizontally** (left and right) ←→
- **Vertically** (up and down) ↕️
- **Diagonally** (in any diagonal direction) ↗️↖️↙️↘️
- **Horizontally** (left and right)
- **Vertically** (up and down)
- **Diagonally** (in any diagonal direction)
She can move as many squares as she wants in these directions!
## The Challenge 🎯
## The Challenge
Let's say we want to solve the **4-Queens problem** (N=4):
- We have a 4×4 chessboard (16 squares total)
@ -45,208 +45,4 @@ Q . . . ← Queen attacks diagonally
. . . X
```
So we can't put any other queen in any of those X positions!
## How Our Program Works 🖥️
### Step 1: Understanding the Input
When you run our program like this:
```bash
./n_queens 4
```
The number `4` means "solve the 4-Queens problem" (4×4 board with 4 queens).
### Step 2: How We Represent the Solution
Instead of drawing the whole board, we use a clever trick! Since we know:
- There must be exactly ONE queen in each row
- There must be exactly ONE queen in each column
We can represent a solution as a list of numbers:
```
1 3 0 2
```
This means:
- **Row 0**: Queen is in column 1
- **Row 1**: Queen is in column 3
- **Row 2**: Queen is in column 0
- **Row 3**: Queen is in column 2
### Step 3: Visualizing the Solution
If we draw this on a 4×4 board:
```
. Q . . ← Row 0, Column 1
. . . Q ← Row 1, Column 3
Q . . . ← Row 2, Column 0
. . Q . ← Row 3, Column 2
```
Let's check: Can any queen attack another?
- Queen at (0,1): Can't attack any other queen ✅
- Queen at (1,3): Can't attack any other queen ✅
- Queen at (2,0): Can't attack any other queen ✅
- Queen at (3,2): Can't attack any other queen ✅
Perfect! This is a valid solution!
## How Our Code Works 🔧
### The Main Function (`main`)
```c
int main(int argc, char **argv)
{
int n;
int *queens;
if (argc != 2) // Check if user gave us exactly one number
return (1);
n = atoi(argv[1]); // Convert the text "4" to number 4
if (n <= 0) // Make sure the number is positive
return (1);
queens = (int *)malloc(sizeof(int) * n); // Create space to store queen positions
if (!queens) // Check if we got the memory
return (1);
solve_nqueens(queens, 0, n); // Start solving from row 0
free(queens); // Clean up memory
return (0);
}
```
**What this does in simple terms:**
1. "Did the user give me a number?"
2. "Is it a good number (positive)?"
3. "Let me create space to remember where I put the queens"
4. "Now let me solve the puzzle!"
5. "Clean up when I'm done"
### The Solver Function (`solve_nqueens`)
This is the "brain" of our program. It uses a technique called **backtracking**:
```c
void solve_nqueens(int *queens, int row, int n)
{
int col;
if (row == n) // Did I place all queens?
{
print_solution(queens, n); // Yes! Print this solution
return ;
}
col = 0;
while (col < n) // Try each column in this row
{
if (is_safe(queens, row, col, n)) // Can I put a queen here?
{
queens[row] = col; // Yes! Put the queen here
solve_nqueens(queens, row + 1, n); // Try the next row
}
col++;
}
}
```
**Think of it like this:**
1. "Am I done placing all queens?" → If yes, print the solution!
2. "If not, let me try putting a queen in each column of this row"
3. "For each column, ask: Is it safe to put a queen here?"
4. "If safe, put the queen there and try to solve the next row"
### The Safety Check (`is_safe`)
This function checks if a queen position is safe:
```c
int is_safe(int *queens, int row, int col, int n)
{
int i;
i = 0;
while (i < row) // Check all previously placed queens
{
if (queens[i] == col) // Same column?
return (0); // Not safe!
if (queens[i] - i == col - row) // Same diagonal (\)?
return (0); // Not safe!
if (queens[i] + i == col + row) // Same diagonal (/)?
return (0); // Not safe!
i++;
}
return (1); // Safe to place queen here!
}
```
**The three checks:**
1. **Same column**: `queens[i] == col`
- "Is there already a queen in this column?"
2. **Diagonal 1**: `queens[i] - i == col - row`
- "Is there a queen on the same diagonal going from top-left to bottom-right?"
3. **Diagonal 2**: `queens[i] + i == col + row`
- "Is there a queen on the same diagonal going from top-right to bottom-left?"
## Example Run 🏃‍♂️
Let's trace through what happens when we run `./n_queens 4`:
1. **Start with row 0**: Try putting a queen in each column
- Column 0: Check safety → Safe! Put queen at (0,0)
- Move to row 1
2. **Row 1**: Try each column
- Column 0: Not safe (same column as row 0)
- Column 1: Not safe (same column... wait, no queen there yet)
- Column 2: Check safety → Safe! Put queen at (1,2)
- Move to row 2
3. **Row 2**: Try each column
- Column 0: Not safe (diagonal conflict)
- Column 1: Not safe (diagonal conflict)
- Column 2: Not safe (same column as row 1)
- Column 3: Not safe (diagonal conflict)
- **No solution found!** Go back to row 1
4. **Back to row 1**: Try next column
- Column 3: Check safety → Safe! Put queen at (1,3)
- Move to row 2
5. Continue this process...
Eventually, we find: `1 3 0 2` and `2 0 3 1`
## Results for Different N Values 📊
- **N=1**: `0` (1 solution - just put the queen anywhere)
- **N=2**: No output (impossible to solve)
- **N=3**: No output (impossible to solve)
- **N=4**: `1 3 0 2` and `2 0 3 1` (2 solutions)
- **N=8**: 92 solutions!
## Fun Facts! 🎉
1. **Why no solution for N=2 and N=3?**
- For N=2: You need 2 queens on a 2×2 board, but they'll always attack each other!
- For N=3: Same problem - not enough space!
2. **The 8-Queens problem** (standard chessboard) has exactly **92 solutions**!
3. **This is a classic computer science problem** that teaches us about:
- **Recursion** (functions calling themselves)
- **Backtracking** (trying something, and if it doesn't work, going back and trying something else)
- **Problem solving** (breaking a big problem into smaller pieces)
## How to Use the Program 💻
1. **Compile**: `make`
2. **Run**: `./n_queens 4`
3. **Test different values**: `make test`
4. **Clean up**: `make clean`
Try it with different numbers and see what happens! 🚀
So we can't put any other queen in any of those X positions!

View File

@ -1,6 +1,6 @@
# Permutations Exercise - Simple Explanation 🔄
# Permutations
## What is a Permutation? 🤔
## What is a Permutation?
Imagine you have some letters, like the letters in your name. A **permutation** is just a fancy word for "all the different ways you can arrange those letters."
@ -10,14 +10,14 @@ Think of it like this:
It's like having alphabet blocks and seeing how many different words you can spell by changing the order!
## The Challenge 🎯
## The Challenge
Your mission is to write a program that:
1. Takes a word (like "abc")
2. Shows ALL possible ways to rearrange the letters
3. Shows them in **alphabetical order** (like in a dictionary)
## Real Examples 📝
## Real Examples
Let's see what our program does:
@ -54,147 +54,3 @@ bca
cab
cba
```
*Why?* Think of it step by step:
- Start with 'a': we can make **abc** and **acb**
- Start with 'b': we can make **bac** and **bca**
- Start with 'c': we can make **cab** and **cba**
## How Our Code Works 🛠️
### Step 1: Getting Ready
```c
// We take the word you give us
char *str = argv[1]; // This is your word like "abc"
// We make a copy so we don't mess up the original
copy = malloc(sizeof(char) * (len + 1));
```
### Step 2: Sorting First (The Secret Sauce! ✨)
```c
ft_sort_string(copy); // This puts letters in order: "cba" becomes "abc"
```
**Why do we sort first?**
- If someone gives us "cba", we sort it to "abc" first
- This way, we always start with letters in alphabetical order
- Then when we make all arrangements, they come out in the right order!
### Step 3: The Magic Swapping Function
```c
void ft_swap(char *a, char *b)
{
char temp = *a; // Remember the first letter
*a = *b; // Put the second letter in first position
*b = temp; // Put the first letter in second position
}
```
**What's swapping?** It's like switching two cards in your hand:
- You have cards **A** and **B**
- After swapping, you have **B** and **A**
### Step 4: The Next Permutation Magic 🪄
```c
int next_permutation(char *str, int len)
{
int i = len - 2;
while (i >= 0 && str[i] >= str[i + 1]) // Find rightmost character smaller than next
i--;
if (i < 0)
return (0); // No more permutations
int j = len - 1;
while (str[j] <= str[i]) // Find rightmost character greater than str[i]
j--;
ft_swap(&str[i], &str[j]); // Swap them
ft_reverse(str, i + 1, len - 1); // Reverse the suffix
return (1); // Successfully generated next permutation
}
```
**How does this work?** Think of it like counting in a special way:
1. **Find** the rightmost place where we can "increment" (make it bigger)
2. **Swap** with the next bigger character available
3. **Reverse** everything after that position to get the smallest arrangement
4. **Repeat** until no more permutations exist
It's like a smart odometer that counts through all possible letter arrangements in perfect alphabetical order!
### Step 5: The Main Loop 🔄
```c
ft_sort_string(copy); // Start with alphabetically first arrangement
puts(copy); // Print the first permutation
while (next_permutation(copy, len)) // While there are more permutations
puts(copy); // Print each one
```
**How does this work?**
1. **Start** with the smallest (first) arrangement: "abc"
2. **Print** it
3. **Generate** the next alphabetical arrangement using `next_permutation`
4. **Print** it
5. **Repeat** until `next_permutation` says "no more!"
It's like flipping through a dictionary - each page (permutation) comes in perfect alphabetical order!
## Why This Approach is Cool 😎
### The Step-by-Step Process 📋
When we have "abc", our program works like this:
```
1. Start: abc (sorted, print it!)
2. Next: acb (swap 'b' and 'c', print it!)
3. Next: bac (find next in alphabetical order, print it!)
4. Next: bca (continue the pattern, print it!)
5. Next: cab (keep going, print it!)
6. Next: cba (last one, print it!)
7. Done: No more permutations possible
```
**The Magic:** Each step finds the next arrangement that would come after the current one in a dictionary! It's like having a super-smart assistant who knows exactly what comes next alphabetically.
### Memory Management 🧠
```c
copy = malloc(sizeof(char) * (len + 1)); // Ask for memory
// ... do our work ...
free(copy); // Give memory back when done
```
We're polite programmers - we clean up after ourselves!
### Error Handling 🛡️
```c
if (argc != 2) // Did you give us exactly one word?
return (1); // If not, we quit
if (!copy) // Did we get the memory we asked for?
return (1); // If not, we quit safely
```
We check if things went wrong and handle it gracefully.
## Fun Facts! 🎉
- With 1 letter: **1** permutation
- With 2 letters: **2** permutations
- With 3 letters: **6** permutations
- With 4 letters: **24** permutations
- With 5 letters: **120** permutations
**Pattern?** For n letters, you get n × (n-1) × (n-2) × ... × 1 permutations!
## Try It Yourself! 🚀
1. Compile the program: `gcc -Wall -Wextra -Werror permutations.c -o permutations`
2. Try it with your name: `./permutations john`
3. Try it with short words: `./permutations cat`
4. See how the results are always in alphabetical order!
Remember: The computer is doing exactly what we told it to do, step by step, just like following a recipe! 👨‍🍳
---
*Made with ❤️ for curious minds who want to understand how permutations work!*

View File

@ -1,4 +1,4 @@
# Powerset Exercise - Simple Explanation 🧮
# Powerset
## What is this exercise about?
@ -6,16 +6,16 @@ Imagine you have a bag of numbered balls, and you want to find all the different
This is exactly what the **powerset** exercise does!
## Real-world example 🎯
## Real-world example
Let's say you have these numbered balls: **1, 2, 3, 4, 5**
And you want to find all the ways to pick balls that add up to **5**.
Here are all the possible ways:
- Pick just ball **5** → 5 = 5
- Pick balls **1** and **4** → 1 + 4 = 5
- Pick balls **2** and **3** → 2 + 3 = 5
- Pick just ball **5** → 5 = 5
- Pick balls **1** and **4** → 1 + 4 = 5
- Pick balls **2** and **3** → 2 + 3 = 5
So the answer would be:
```
@ -23,153 +23,3 @@ So the answer would be:
1 4
2 3
```
## How does our program work? 🤖
### Step 1: Understanding the input
When you run the program like this:
```bash
./powerset 5 1 2 3 4 5
```
- **5** is our target number (what we want the balls to add up to)
- **1 2 3 4 5** are our numbered balls
### Step 2: The magic behind the scenes
Our program is like a smart robot that tries **every possible combination**:
1. **Try no balls at all** → sum = 0 (not 5, so skip)
2. **Try just ball 1** → sum = 1 (not 5, so skip)
3. **Try just ball 2** → sum = 2 (not 5, so skip)
4. **Try just ball 3** → sum = 3 (not 5, so skip)
5. **Try just ball 4** → sum = 4 (not 5, so skip)
6. **Try just ball 5** → sum = 5 ✅ **FOUND ONE!**
7. **Try balls 1 and 2** → sum = 3 (not 5, so skip)
8. **Try balls 1 and 3** → sum = 4 (not 5, so skip)
9. **Try balls 1 and 4** → sum = 5 ✅ **FOUND ANOTHER!**
10. **Try balls 2 and 3** → sum = 5 ✅ **FOUND ANOTHER!**
...and so on until it tries every possible combination!
## Code explanation 📝
### The main parts of our code:
#### 1. Reading the input (`main` function)
```c
target = atoi(argv[1]); // Get the target number (5 in our example)
set[i] = atoi(argv[i + 2]); // Get each ball number (1, 2, 3, 4, 5)
```
#### 2. The smart robot (`find_subsets` function)
This function is like our robot that tries every combination:
```c
// For each ball, we have 2 choices:
find_subsets(..., index + 1); // Don't pick this ball
subset[subset_size] = set[index]; // Pick this ball
find_subsets(..., subset_size + 1, ...); // Continue with this ball included
```
#### 3. Checking if we found a winner (`print_subset`)
```c
if (current_sum == target) // If the sum equals our target
print_subset(subset, subset_size); // Show this combination!
```
## More examples to understand better 🎲
### Example 1: Finding combinations that sum to 3
```bash
./powerset 3 1 0 2 4 5 3
```
**What the robot finds:**
- Ball **3** alone → 3 ✅
- Balls **0** and **3** → 0 + 3 = 3 ✅
- Balls **1** and **2** → 1 + 2 = 3 ✅
- Balls **1**, **0**, and **2** → 1 + 0 + 2 = 3 ✅
**Output:**
```
3
0 3
1 2
1 0 2
```
### Example 2: Finding the empty combination
```bash
./powerset 0 1 -1
```
**What the robot finds:**
- No balls picked → sum = 0 ✅ (shows as empty line)
- Balls **1** and **-1** → 1 + (-1) = 0 ✅
**Output:**
```
1 -1
```
(Notice the empty line at the top!)
### Example 3: When nothing works
```bash
./powerset 7 3 8 2
```
**What the robot finds:**
- No combination of 3, 8, and 2 can make 7
- So nothing gets printed (empty output)
## Important rules 📏
1. **Order matters**: We always keep balls in the same order as given
- ✅ Correct: `1 4` (1 comes before 4 in input)
- ❌ Wrong: `4 1` (this changes the order)
2. **No duplicates**: Each ball can only be used once per combination
3. **Empty combination counts**: If target is 0, picking no balls is valid!
## How to use the program 🚀
1. **Compile it:**
```bash
make
```
2. **Run tests:**
```bash
make test
```
3. **Try your own examples:**
```bash
./powerset [target_number] [ball1] [ball2] [ball3] ...
```
4. **Clean up:**
```bash
make clean # Remove temporary files
make fclean # Remove everything
```
## Fun challenge! 🎮
Try to predict what this will output before running it:
```bash
./powerset 6 1 2 3 4
```
**Think about it:**
- Which combinations of 1, 2, 3, 4 add up to 6?
- Remember: order matters and each number can only be used once!
**Answer:** `2 4` and `1 2 3` (because 2+4=6 and 1+2+3=6)
---
*Now you understand how the powerset exercise works! It's like having a super-smart robot that can instantly try every possible combination of numbers to find the ones that add up to your target. Pretty cool, right?* 🤖✨

View File

@ -26,154 +26,8 @@ This means:
1. Open door 1: `(`
2. Open door 2: `(`
3. Close door 2: `)`
4. But door 1 is still open! 😱
4. But door 1 is still open!
To fix this, we need to either:
- Remove one of the opening doors: ` ()` (remove first `(`)
- Or remove one of the opening doors: `( )` (remove second `(`)
Both solutions work!
## How Our Program Works
### Step 1: Count the Problems
```c
// This function counts how many parentheses we need to remove
void calculate_removals(char *str, int *left_rem, int *right_rem)
{
int left = 0; // Count of unmatched opening parentheses
int right = 0; // Count of unmatched closing parentheses
// Go through each character
while (str[i])
{
if (str[i] == '(')
left++; // Found an opening door
else if (str[i] == ')')
{
if (left > 0)
left--; // Found a closing door for an open one
else
right++; // Found a closing door with no matching open door
}
}
}
```
**Example with `"(()"`:**
- Start: `left = 0`, `right = 0`
- See `(`: `left = 1` (one unmatched opening)
- See `(`: `left = 2` (two unmatched openings)
- See `)`: `left = 1` (one opening got matched)
- End: `left = 1`, `right = 0`
So we need to remove **1 opening parenthesis**.
### Step 2: Try All Possible Solutions
Think of it like trying different combinations:
```c
// This function tries removing different parentheses to find all valid solutions
void solve(char *s, int pos, int left_rem, int right_rem, int open, char *path)
{
// If we've looked at all characters
if (pos == len)
{
// Check if we removed exactly what we needed and everything balances
if (left_rem == 0 && right_rem == 0 && open == 0)
add_result(results, path); // This is a valid solution!
return;
}
// Try removing this parenthesis (replace with space)
if (s[pos] == '(' && left_rem > 0)
{
path[pos] = ' '; // Replace with space
solve(s, pos + 1, left_rem - 1, right_rem, open, path);
}
// Try keeping this parenthesis
path[pos] = s[pos];
if (s[pos] == '(')
solve(s, pos + 1, left_rem, right_rem, open + 1, path);
// ... and so on
}
```
### Step 3: Avoid Duplicates
We use a list to store all unique solutions:
```c
// This makes sure we don't print the same solution twice
void add_result(t_result **results, char *str)
{
// Check if we already have this solution
current = *results;
while (current)
{
if (ft_strcmp(current->str, str) == 0)
return; // Already have it, don't add again
current = current->next;
}
// It's new, so add it to our list
new->str = ft_strdup(str);
new->next = *results;
*results = new;
}
```
## Example Walkthrough
Let's trace through `"(()"` step by step:
### Initial Analysis:
- Need to remove 1 opening parenthesis (`left_rem = 1`)
- Need to remove 0 closing parentheses (`right_rem = 0`)
### Trying Different Positions:
**Position 0 (first `(`):**
- Try removing it: `" ()"`
- Check: removed 1 opening ✓, no unmatched doors ✓
- **Valid solution!**
**Position 1 (second `(`):**
- Try removing it: `"( )"`
- Check: removed 1 opening ✓, no unmatched doors ✓
- **Valid solution!**
**Position 2 (the `)`):**
- Can't remove it (we need to remove openings, not closings)
### Final Output:
```
()
( )
```
## More Complex Example: `"()())()"`
This string has:
- 3 opening doors: `(`, `(`, `(`
- 4 closing doors: `)`, `)`, `)`, `)`
So we have 1 extra closing door that needs to be removed.
**All possible solutions:**
- Remove closing at position 2: `"()( )()"`
- Remove closing at position 3: `"()() ()"`
- Remove closing at position 4: `"( ())()"`
## Why This Exercise is Useful
This problem teaches us:
1. **Problem-solving**: Break down complex problems into smaller steps
2. **Recursion**: Try all possibilities systematically
3. **Data structures**: Use lists to store and manage results
4. **Optimization**: Find the minimum changes needed
It's like being a **door inspector** - you need to make sure every building (string) has properly matched doors (parentheses) with the minimum number of changes!

36
level-2/tsp/README.md Normal file
View File

@ -0,0 +1,36 @@
# Traveling Salesman Problem (TSP)
## 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!

View File

@ -1,247 +0,0 @@
# 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! 🎉