removed dups
This commit is contained in:
parent
259d4ef6f3
commit
0ec1385e07
@ -1,74 +0,0 @@
|
||||
# Program name
|
||||
NAME = n_queens
|
||||
|
||||
# Compiler and flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
|
||||
# Source files
|
||||
SRCS = n_queens.c
|
||||
|
||||
# Object files
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Header files
|
||||
HEADERS = n_queens.h
|
||||
|
||||
# Colors for output
|
||||
GREEN = \033[0;32m
|
||||
RED = \033[0;31m
|
||||
RESET = \033[0m
|
||||
|
||||
# Main rule
|
||||
all: $(NAME)
|
||||
|
||||
# Compile the program
|
||||
$(NAME): $(OBJS)
|
||||
@echo "$(GREEN)Compiling $(NAME)...$(RESET)"
|
||||
@$(CC) $(CFLAGS) $(OBJS) -o $(NAME)
|
||||
@echo "$(GREEN)✓ $(NAME) compiled successfully!$(RESET)"
|
||||
|
||||
# Compile object files
|
||||
%.o: %.c $(HEADERS)
|
||||
@echo "Compiling $<..."
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Clean object files
|
||||
clean:
|
||||
@echo "$(RED)Cleaning object files...$(RESET)"
|
||||
@rm -f $(OBJS)
|
||||
@echo "$(RED)✓ Object files cleaned!$(RESET)"
|
||||
|
||||
# Clean everything
|
||||
fclean: clean
|
||||
@echo "$(RED)Cleaning executable...$(RESET)"
|
||||
@rm -f $(NAME)
|
||||
@echo "$(RED)✓ Everything cleaned!$(RESET)"
|
||||
|
||||
# Rebuild everything
|
||||
re: fclean all
|
||||
|
||||
# Test the program with different values
|
||||
test: $(NAME)
|
||||
@echo "$(GREEN)Testing n_queens program:$(RESET)"
|
||||
@echo "\n$(GREEN)Testing with n=1:$(RESET)"
|
||||
@./$(NAME) 1
|
||||
@echo "\n$(GREEN)Testing with n=2 (no solutions):$(RESET)"
|
||||
@./$(NAME) 2 || echo "No solutions found"
|
||||
@echo "\n$(GREEN)Testing with n=4:$(RESET)"
|
||||
@./$(NAME) 4
|
||||
@echo "\n$(GREEN)Testing with n=8 (counting solutions):$(RESET)"
|
||||
@echo "Number of solutions for n=8: $$(./$(NAME) 8 | wc -l)"
|
||||
|
||||
# Display help
|
||||
help:
|
||||
@echo "$(GREEN)Available commands:$(RESET)"
|
||||
@echo " make - Compile the program"
|
||||
@echo " make clean - Remove object files"
|
||||
@echo " make fclean - Remove all generated files"
|
||||
@echo " make re - Rebuild everything"
|
||||
@echo " make test - Run tests with different values"
|
||||
@echo " make help - Show this help message"
|
||||
|
||||
# Declare phony targets
|
||||
.PHONY: all clean fclean re test help
|
||||
@ -1,252 +0,0 @@
|
||||
# N-Queens Problem - Simple Explanation 👑
|
||||
|
||||
## 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? ♛
|
||||
|
||||
A queen is the strongest piece in chess. She can move:
|
||||
- **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 🎯
|
||||
|
||||
Let's say we want to solve the **4-Queens problem** (N=4):
|
||||
- We have a 4×4 chessboard (16 squares total)
|
||||
- We need to place 4 queens
|
||||
- **NO queen can attack any other queen**
|
||||
|
||||
### Example: What Does "Attack" Mean?
|
||||
|
||||
If we put a queen at position (0,0) - that's the top-left corner - she can attack:
|
||||
|
||||
```
|
||||
Q . . . ← Queen here attacks all positions marked with X
|
||||
X . . .
|
||||
X . . .
|
||||
X . . .
|
||||
```
|
||||
|
||||
```
|
||||
Q X X X ← Queen attacks horizontally
|
||||
. . . .
|
||||
. . . .
|
||||
. . . .
|
||||
```
|
||||
|
||||
```
|
||||
Q . . . ← Queen attacks diagonally
|
||||
. X . .
|
||||
. . X .
|
||||
. . . 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! 🚀
|
||||
@ -1,84 +0,0 @@
|
||||
#include "n_queens.h"
|
||||
|
||||
void print_number(int n)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (n >= 10)
|
||||
print_number(n / 10);
|
||||
c = '0' + (n % 10);
|
||||
write(1, &c, 1);
|
||||
}
|
||||
|
||||
void print_solution(int *queens, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < n)
|
||||
{
|
||||
if (i > 0)
|
||||
write(1, " ", 1);
|
||||
print_number(queens[i]);
|
||||
i++;
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
|
||||
int is_safe(int *queens, int row, int col, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)n;
|
||||
i = 0;
|
||||
while (i < row)
|
||||
{
|
||||
if (queens[i] == col)
|
||||
return (0);
|
||||
if (queens[i] - i == col - row)
|
||||
return (0);
|
||||
if (queens[i] + i == col + row)
|
||||
return (0);
|
||||
i++;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
void solve_nqueens(int *queens, int row, int n)
|
||||
{
|
||||
int col;
|
||||
|
||||
if (row == n)
|
||||
{
|
||||
print_solution(queens, n);
|
||||
return ;
|
||||
}
|
||||
col = 0;
|
||||
while (col < n)
|
||||
{
|
||||
if (is_safe(queens, row, col, n))
|
||||
{
|
||||
queens[row] = col;
|
||||
solve_nqueens(queens, row + 1, n);
|
||||
}
|
||||
col++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
int *queens;
|
||||
|
||||
if (argc != 2)
|
||||
return (1);
|
||||
n = atoi(argv[1]);
|
||||
if (n <= 0)
|
||||
return (1);
|
||||
queens = (int *)malloc(sizeof(int) * n);
|
||||
if (!queens)
|
||||
return (1);
|
||||
solve_nqueens(queens, 0, n);
|
||||
free(queens);
|
||||
return (0);
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
#ifndef N_QUEENS_H
|
||||
# define N_QUEENS_H
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <stdio.h>
|
||||
|
||||
int is_safe(int *queens, int row, int col, int n);
|
||||
void solve_nqueens(int *queens, int row, int n);
|
||||
void print_solution(int *queens, int n);
|
||||
void print_number(int n);
|
||||
|
||||
#endif
|
||||
@ -1,28 +0,0 @@
|
||||
Assignement name : n_queens
|
||||
|
||||
Expected files : *.c *.h
|
||||
|
||||
Allowed functions : atoi, fprintf, write, calloc, malloc, free, realloc, stdout, stderr
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Write a program that will print all the solutions to the n queens problem
|
||||
for a n given as argument.
|
||||
We will not test with negative values.
|
||||
The order of the solutions is not important.
|
||||
|
||||
You will display the solutions under the following format :
|
||||
<p1> <p2> <p3> ... \n
|
||||
where pn are the line index of the queen in each colum starting from 0.
|
||||
|
||||
For example this should work :
|
||||
$> ./n_queens 2 | cat -e
|
||||
|
||||
$> ./n_queens 4 | cat -e
|
||||
1 3 0 2$
|
||||
2 0 3 1$
|
||||
|
||||
$> ./n_queens 7 | cat -e
|
||||
0 2 4 6 1 3 5$
|
||||
0 3 6 2 5 1 4$
|
||||
etc...
|
||||
@ -1,25 +0,0 @@
|
||||
NAME = permutations
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
|
||||
SRCS = permutations.c
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
$(NAME): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $(NAME) $(OBJS)
|
||||
|
||||
%.o: %.c permutations.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
|
||||
fclean: clean
|
||||
rm -f $(NAME)
|
||||
|
||||
re: fclean all
|
||||
|
||||
.PHONY: all clean fclean re
|
||||
@ -1,200 +0,0 @@
|
||||
# Permutations Exercise - Simple Explanation 🔄
|
||||
|
||||
## 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."
|
||||
|
||||
Think of it like this:
|
||||
- If you have the letters **A** and **B**, you can arrange them as **AB** or **BA**
|
||||
- If you have **A**, **B**, and **C**, you can make **ABC**, **ACB**, **BAC**, **BCA**, **CAB**, **CBA**
|
||||
|
||||
It's like having alphabet blocks and seeing how many different words you can spell by changing the order!
|
||||
|
||||
## 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 📝
|
||||
|
||||
Let's see what our program does:
|
||||
|
||||
### Example 1: Single Letter
|
||||
```bash
|
||||
./permutations a
|
||||
```
|
||||
**Output:** `a`
|
||||
|
||||
*Why?* There's only one letter, so there's only one way to arrange it!
|
||||
|
||||
### Example 2: Two Letters
|
||||
```bash
|
||||
./permutations ab
|
||||
```
|
||||
**Output:**
|
||||
```
|
||||
ab
|
||||
ba
|
||||
```
|
||||
|
||||
*Why?* We can put 'a' first or 'b' first. That's it!
|
||||
|
||||
### Example 3: Three Letters
|
||||
```bash
|
||||
./permutations abc
|
||||
```
|
||||
**Output:**
|
||||
```
|
||||
abc
|
||||
acb
|
||||
bac
|
||||
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!*
|
||||
@ -1,98 +0,0 @@
|
||||
#include "permutations.h"
|
||||
|
||||
int ft_strlen(char *str)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
while (str[len])
|
||||
len++;
|
||||
return (len);
|
||||
}
|
||||
|
||||
void ft_swap(char *a, char *b)
|
||||
{
|
||||
char temp;
|
||||
|
||||
temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
void ft_sort_string(char *str)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int len;
|
||||
|
||||
len = ft_strlen(str);
|
||||
i = 0;
|
||||
while (i < len - 1)
|
||||
{
|
||||
j = i + 1;
|
||||
while (j < len)
|
||||
{
|
||||
if (str[i] > str[j])
|
||||
ft_swap(&str[i], &str[j]);
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void ft_reverse(char *str, int start, int end)
|
||||
{
|
||||
while (start < end)
|
||||
{
|
||||
ft_swap(&str[start], &str[end]);
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
int next_permutation(char *str, int len)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
i = len - 2;
|
||||
while (i >= 0 && str[i] >= str[i + 1])
|
||||
i--;
|
||||
if (i < 0)
|
||||
return (0);
|
||||
j = len - 1;
|
||||
while (str[j] <= str[i])
|
||||
j--;
|
||||
ft_swap(&str[i], &str[j]);
|
||||
ft_reverse(str, i + 1, len - 1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *str;
|
||||
char *copy;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
if (argc != 2)
|
||||
return (1);
|
||||
str = argv[1];
|
||||
len = ft_strlen(str);
|
||||
copy = malloc(sizeof(char) * (len + 1));
|
||||
if (!copy)
|
||||
return (1);
|
||||
i = 0;
|
||||
while (i < len)
|
||||
{
|
||||
copy[i] = str[i];
|
||||
i++;
|
||||
}
|
||||
copy[len] = '\0';
|
||||
ft_sort_string(copy);
|
||||
puts(copy);
|
||||
while (next_permutation(copy, len))
|
||||
puts(copy);
|
||||
free(copy);
|
||||
return (0);
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
#ifndef PERMUTATIONS_H
|
||||
# define PERMUTATIONS_H
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <stdio.h>
|
||||
|
||||
void ft_swap(char *a, char *b);
|
||||
void ft_sort_string(char *str);
|
||||
void ft_reverse(char *str, int start, int end);
|
||||
int next_permutation(char *str, int len);
|
||||
int ft_strlen(char *str);
|
||||
|
||||
#endif
|
||||
@ -1,27 +0,0 @@
|
||||
Assignment name : permutations
|
||||
Expected files : *.c *.h
|
||||
Allowed functions: puts, malloc, calloc, realloc, free, write
|
||||
---------------------------------------------------------------
|
||||
|
||||
Write a program that will print all the permutations of a string given as argument.
|
||||
|
||||
The solutions must be given in alphabetical order.
|
||||
|
||||
We will not try your program with strings containing duplicates (eg: 'abccd').
|
||||
|
||||
For example this should work:
|
||||
|
||||
$> ./permutations a | cat -e
|
||||
a$
|
||||
|
||||
$> ./permutations ab | cat -e
|
||||
ab$
|
||||
ba$
|
||||
|
||||
$> ./permutations abc | cat -e
|
||||
abc$
|
||||
acb$
|
||||
bac$
|
||||
bca$
|
||||
cab$
|
||||
cba$
|
||||
@ -1,71 +0,0 @@
|
||||
# Program name
|
||||
NAME = powerset
|
||||
|
||||
# Compiler and flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
|
||||
# Source files
|
||||
SRCS = powerset.c
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Header files
|
||||
HEADERS = powerset.h
|
||||
|
||||
# Colors for output
|
||||
GREEN = \033[0;32m
|
||||
RED = \033[0;31m
|
||||
RESET = \033[0m
|
||||
|
||||
# Default target
|
||||
all: $(NAME)
|
||||
|
||||
# Build the program
|
||||
$(NAME): $(OBJS)
|
||||
@echo "$(GREEN)Linking $(NAME)...$(RESET)"
|
||||
@$(CC) $(CFLAGS) $(OBJS) -o $(NAME)
|
||||
@echo "$(GREEN)✓ $(NAME) compiled successfully!$(RESET)"
|
||||
|
||||
# Compile source files to object files
|
||||
%.o: %.c $(HEADERS)
|
||||
@echo "$(GREEN)Compiling $<...$(RESET)"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Clean object files
|
||||
clean:
|
||||
@echo "$(RED)Cleaning object files...$(RESET)"
|
||||
@rm -f $(OBJS)
|
||||
|
||||
# Clean everything
|
||||
fclean: clean
|
||||
@echo "$(RED)Cleaning $(NAME)...$(RESET)"
|
||||
@rm -f $(NAME)
|
||||
|
||||
# Rebuild everything
|
||||
re: fclean all
|
||||
|
||||
# Test the program with the examples from the subject
|
||||
test: $(NAME)
|
||||
@echo "$(GREEN)Running tests...$(RESET)"
|
||||
@echo "\n$(GREEN)Test 1: powerset 3 1 0 2 4 5 3$(RESET)"
|
||||
@./$(NAME) 3 1 0 2 4 5 3
|
||||
@echo "\n$(GREEN)Test 2: powerset 12 5 2 1 8 4 3 7 11$(RESET)"
|
||||
@./$(NAME) 12 5 2 1 8 4 3 7 11
|
||||
@echo "\n$(GREEN)Test 3: powerset 0 1 -1$(RESET)"
|
||||
@./$(NAME) 0 1 -1
|
||||
@echo "\n$(GREEN)Test 4: powerset 7 3 8 2 (should be empty)$(RESET)"
|
||||
@./$(NAME) 7 3 8 2
|
||||
@echo "$(GREEN)✓ All tests completed!$(RESET)"
|
||||
|
||||
# Help
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo " all - Build the program (default)"
|
||||
@echo " clean - Remove object files"
|
||||
@echo " fclean - Remove object files and executable"
|
||||
@echo " re - Rebuild everything"
|
||||
@echo " test - Run test cases"
|
||||
@echo " help - Show this help message"
|
||||
|
||||
# Declare phony targets
|
||||
.PHONY: all clean fclean re test help
|
||||
@ -1,175 +0,0 @@
|
||||
# Powerset Exercise - Simple Explanation 🧮
|
||||
|
||||
## What is this exercise about?
|
||||
|
||||
Imagine you have a bag of numbered balls, and you want to find all the different ways you can pick some balls so that the numbers on them add up to a specific target number.
|
||||
|
||||
This is exactly what the **powerset** exercise does!
|
||||
|
||||
## 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 ✅
|
||||
|
||||
So the answer would be:
|
||||
```
|
||||
5
|
||||
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?* 🤖✨
|
||||
@ -1,73 +0,0 @@
|
||||
#include "powerset.h"
|
||||
|
||||
void print_subset(int *subset, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < size)
|
||||
{
|
||||
printf("%d", subset[i]);
|
||||
if (i < size - 1)
|
||||
printf(" ");
|
||||
i++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void find_subsets(int *set, int set_size, int target, int *subset,
|
||||
int subset_size, int index)
|
||||
{
|
||||
int current_sum;
|
||||
int i;
|
||||
|
||||
if (index == set_size)
|
||||
{
|
||||
current_sum = 0;
|
||||
i = 0;
|
||||
while (i < subset_size)
|
||||
{
|
||||
current_sum += subset[i];
|
||||
i++;
|
||||
}
|
||||
if (current_sum == target)
|
||||
print_subset(subset, subset_size);
|
||||
return ;
|
||||
}
|
||||
find_subsets(set, set_size, target, subset, subset_size, index + 1);
|
||||
subset[subset_size] = set[index];
|
||||
find_subsets(set, set_size, target, subset, subset_size + 1, index + 1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int *set;
|
||||
int *subset;
|
||||
int target;
|
||||
int set_size;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
return (1);
|
||||
target = atoi(argv[1]);
|
||||
set_size = argc - 2;
|
||||
set = malloc(sizeof(int) * set_size);
|
||||
if (!set)
|
||||
return (1);
|
||||
subset = malloc(sizeof(int) * set_size);
|
||||
if (!subset)
|
||||
{
|
||||
free(set);
|
||||
return (1);
|
||||
}
|
||||
i = 0;
|
||||
while (i < set_size)
|
||||
{
|
||||
set[i] = atoi(argv[i + 2]);
|
||||
i++;
|
||||
}
|
||||
find_subsets(set, set_size, target, subset, 0, 0);
|
||||
free(set);
|
||||
free(subset);
|
||||
return (0);
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
#ifndef POWERSET_H
|
||||
# define POWERSET_H
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <stdio.h>
|
||||
|
||||
void find_subsets(int *set, int set_size, int target, int *subset,
|
||||
int subset_size, int index);
|
||||
void print_subset(int *subset, int size);
|
||||
|
||||
#endif
|
||||
@ -1,65 +0,0 @@
|
||||
Assignment name : powerset
|
||||
Expected files : *.c *.h
|
||||
Allowed functions: atoi, printf, fprintf, malloc, calloc, realloc, free, stdout,
|
||||
write
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Write a program that will take as argument an integer n followed by a set s of
|
||||
distinct integers.
|
||||
Your program should display all the subsets of s whose sum of elements is n.
|
||||
|
||||
The order of the lines is not important, but the order of the elements in a subset is:
|
||||
it must match the order in the initial set s.
|
||||
This way, you should not have any duplicates (eg: '1 2' and '2 1').
|
||||
For example, using the command ./powerset 5 1 2 3 4 5
|
||||
this output is valid:
|
||||
1 4
|
||||
2 3
|
||||
5
|
||||
this one is also valid:
|
||||
2 3
|
||||
5
|
||||
1 4
|
||||
but not this one:
|
||||
4 1
|
||||
3 2
|
||||
5
|
||||
|
||||
|
||||
In case of a malloc error your program will exit with the code 1.
|
||||
|
||||
We will not test with invalid sets (for example '1 1 2').
|
||||
|
||||
Hint: the empty subset is a valid subset of any set. It will be displayed as an empty line.
|
||||
|
||||
For example this should work:
|
||||
$> ./powerset 3 1 0 2 4 5 3 | cat -e
|
||||
3$
|
||||
0 3$
|
||||
1 2$
|
||||
1 0 2$
|
||||
$> ./powerset 12 5 2 1 8 4 3 7 11 | cat -e
|
||||
8 4$
|
||||
1 11$
|
||||
1 4 7$
|
||||
1 8 3$
|
||||
2 3 7$
|
||||
5 7$
|
||||
5 4 3$
|
||||
5 2 1 4$
|
||||
$> ./powerset 0 1 -1 | cat -e
|
||||
$
|
||||
1 -1$
|
||||
$> ./powerset 7 3 8 2 | cat -e
|
||||
|
||||
// Other tests:
|
||||
$> ./powerset 100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | cat -e
|
||||
...
|
||||
$> ./powerset -1 1 2 3 4 5 -10 | cat -e
|
||||
...
|
||||
$> ./powerset 0 -1 1 2 3 -2 | cat -e
|
||||
...
|
||||
$> ./powerset 13 65 23 3 4 6 7 1 2 | cat -e
|
||||
...
|
||||
$> ./powerset 10 0 1 2 3 4 5 6 7 8 9 | cat -e
|
||||
...
|
||||
80
rip/Makefile
80
rip/Makefile
@ -1,80 +0,0 @@
|
||||
# Program name
|
||||
NAME = rip
|
||||
|
||||
# Compiler and flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
|
||||
# Source files
|
||||
SRCS = rip.c
|
||||
|
||||
# Object files
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Colors for output
|
||||
GREEN = \033[0;32m
|
||||
RED = \033[0;31m
|
||||
YELLOW = \033[0;33m
|
||||
NC = \033[0m # No Color
|
||||
|
||||
# Default target
|
||||
all: $(NAME)
|
||||
|
||||
# Build the executable
|
||||
$(NAME): $(OBJS)
|
||||
@echo "$(YELLOW)Linking $(NAME)...$(NC)"
|
||||
@$(CC) $(CFLAGS) $(OBJS) -o $(NAME)
|
||||
@echo "$(GREEN)✅ $(NAME) created successfully!$(NC)"
|
||||
|
||||
# Compile source files to object files
|
||||
%.o: %.c
|
||||
@echo "$(YELLOW)Compiling $<...$(NC)"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Clean object files
|
||||
clean:
|
||||
@echo "$(RED)🧹 Cleaning object files...$(NC)"
|
||||
@rm -f $(OBJS)
|
||||
@echo "$(GREEN)✅ Object files cleaned!$(NC)"
|
||||
|
||||
# Clean object files and executable
|
||||
fclean: clean
|
||||
@echo "$(RED)🧹 Cleaning executable...$(NC)"
|
||||
@rm -f $(NAME)
|
||||
@echo "$(GREEN)✅ Everything cleaned!$(NC)"
|
||||
|
||||
# Rebuild everything
|
||||
re: fclean all
|
||||
|
||||
# Test the program with provided examples
|
||||
test: $(NAME)
|
||||
@echo "$(YELLOW)🧪 Running tests...$(NC)"
|
||||
@echo "$(YELLOW)Test 1: '(()'$(NC)"
|
||||
@./$(NAME) '(((' | cat -e
|
||||
@echo "$(YELLOW)Test 2: '((()()())())'$(NC)"
|
||||
@./$(NAME) '((()()())())' | cat -e
|
||||
@echo "$(YELLOW)Test 3: '()())()''$(NC)"
|
||||
@./$(NAME) '()())()' | cat -e
|
||||
@echo "$(YELLOW)Test 4: '(()(()('$(NC)"
|
||||
@./$(NAME) '(()(()(' | cat -e
|
||||
@echo "$(GREEN)✅ All tests completed!$(NC)"
|
||||
|
||||
# Check for memory leaks (requires valgrind)
|
||||
valgrind: $(NAME)
|
||||
@echo "$(YELLOW)🔍 Checking for memory leaks...$(NC)"
|
||||
@valgrind --leak-check=full --show-leak-kinds=all ./$(NAME) '(()'
|
||||
@echo "$(GREEN)✅ Memory check completed!$(NC)"
|
||||
|
||||
# Show help
|
||||
help:
|
||||
@echo "$(GREEN)Available targets:$(NC)"
|
||||
@echo " $(YELLOW)all$(NC) - Build the program"
|
||||
@echo " $(YELLOW)clean$(NC) - Remove object files"
|
||||
@echo " $(YELLOW)fclean$(NC) - Remove object files and executable"
|
||||
@echo " $(YELLOW)re$(NC) - Rebuild everything (fclean + all)"
|
||||
@echo " $(YELLOW)test$(NC) - Run all test cases"
|
||||
@echo " $(YELLOW)valgrind$(NC) - Check for memory leaks"
|
||||
@echo " $(YELLOW)help$(NC) - Show this help message"
|
||||
|
||||
# Declare phony targets
|
||||
.PHONY: all clean fclean re test valgrind help
|
||||
179
rip/README.md
179
rip/README.md
@ -1,179 +0,0 @@
|
||||
# The Parentheses Balancing Problem (RIP Exercise)
|
||||
|
||||
## What is this exercise about?
|
||||
|
||||
Imagine you have a string of parentheses like this: `"(()"`.
|
||||
|
||||
Think of parentheses like **doors** in a building:
|
||||
- `(` is like **opening a door**
|
||||
- `)` is like **closing a door**
|
||||
|
||||
For everything to work properly, every door you open must have a matching door that closes it!
|
||||
|
||||
## The Problem
|
||||
|
||||
Sometimes we get strings where the doors don't match properly. For example:
|
||||
- `"((("` - We opened 3 doors but never closed any!
|
||||
- `"())"` - We opened 1 door, closed 1 door, but then tried to close another door that was never opened!
|
||||
|
||||
Our job is to **fix** these strings by removing the minimum number of parentheses (but replacing them with spaces instead of deleting them completely).
|
||||
|
||||
## Real-World Example
|
||||
|
||||
Let's say you have: `"(()"`
|
||||
|
||||
This means:
|
||||
1. Open door 1: `(`
|
||||
2. Open door 2: `(`
|
||||
3. Close door 2: `)`
|
||||
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!
|
||||
180
rip/rip.c
180
rip/rip.c
@ -1,180 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct s_result
|
||||
{
|
||||
char *str;
|
||||
struct s_result *next;
|
||||
} t_result;
|
||||
|
||||
int ft_strlen(char *str)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
while (str[len])
|
||||
len++;
|
||||
return (len);
|
||||
}
|
||||
|
||||
int ft_strcmp(char *s1, char *s2)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (s1[i] && s2[i] && s1[i] == s2[i])
|
||||
i++;
|
||||
return (s1[i] - s2[i]);
|
||||
}
|
||||
|
||||
char *ft_strdup(char *src)
|
||||
{
|
||||
char *dup;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
len = ft_strlen(src);
|
||||
dup = malloc(len + 1);
|
||||
if (!dup)
|
||||
return (NULL);
|
||||
i = 0;
|
||||
while (i < len)
|
||||
{
|
||||
dup[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
dup[len] = '\0';
|
||||
return (dup);
|
||||
}
|
||||
|
||||
void add_result(t_result **results, char *str)
|
||||
{
|
||||
t_result *new;
|
||||
t_result *current;
|
||||
|
||||
current = *results;
|
||||
while (current)
|
||||
{
|
||||
if (ft_strcmp(current->str, str) == 0)
|
||||
return ;
|
||||
current = current->next;
|
||||
}
|
||||
new = malloc(sizeof(t_result));
|
||||
if (!new)
|
||||
return ;
|
||||
new->str = ft_strdup(str);
|
||||
if (!new->str)
|
||||
{
|
||||
free(new);
|
||||
return ;
|
||||
}
|
||||
new->next = *results;
|
||||
*results = new;
|
||||
}
|
||||
|
||||
void print_results(t_result *results)
|
||||
{
|
||||
t_result *current;
|
||||
int i;
|
||||
|
||||
current = results;
|
||||
while (current)
|
||||
{
|
||||
i = 0;
|
||||
while (current->str[i])
|
||||
{
|
||||
write(1, ¤t->str[i], 1);
|
||||
i++;
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
void free_results(t_result *results)
|
||||
{
|
||||
t_result *temp;
|
||||
|
||||
while (results)
|
||||
{
|
||||
temp = results;
|
||||
results = results->next;
|
||||
free(temp->str);
|
||||
free(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void solve(char *s, int pos, int left_rem, int right_rem, int open, char *path, t_result **results)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = ft_strlen(s);
|
||||
if (pos == len)
|
||||
{
|
||||
if (left_rem == 0 && right_rem == 0 && open == 0)
|
||||
add_result(results, path);
|
||||
return ;
|
||||
}
|
||||
if (s[pos] == '(' && left_rem > 0)
|
||||
{
|
||||
path[pos] = ' ';
|
||||
solve(s, pos + 1, left_rem - 1, right_rem, open, path, results);
|
||||
}
|
||||
if (s[pos] == ')' && right_rem > 0)
|
||||
{
|
||||
path[pos] = ' ';
|
||||
solve(s, pos + 1, left_rem, right_rem - 1, open, path, results);
|
||||
}
|
||||
path[pos] = s[pos];
|
||||
if (s[pos] == '(')
|
||||
solve(s, pos + 1, left_rem, right_rem, open + 1, path, results);
|
||||
else if (s[pos] == ')' && open > 0)
|
||||
solve(s, pos + 1, left_rem, right_rem, open - 1, path, results);
|
||||
else
|
||||
solve(s, pos + 1, left_rem, right_rem, open, path, results);
|
||||
}
|
||||
|
||||
void remove_invalid_parentheses(char *s)
|
||||
{
|
||||
int left_rem;
|
||||
int right_rem;
|
||||
int len;
|
||||
char *path;
|
||||
int i;
|
||||
t_result *results;
|
||||
|
||||
left_rem = 0;
|
||||
right_rem = 0;
|
||||
len = ft_strlen(s);
|
||||
results = NULL;
|
||||
i = 0;
|
||||
while (s[i])
|
||||
{
|
||||
if (s[i] == '(')
|
||||
left_rem++;
|
||||
else if (s[i] == ')')
|
||||
{
|
||||
if (left_rem > 0)
|
||||
left_rem--;
|
||||
else
|
||||
right_rem++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
path = malloc(len + 1);
|
||||
if (!path)
|
||||
return ;
|
||||
path[len] = '\0';
|
||||
solve(s, 0, left_rem, right_rem, 0, path, &results);
|
||||
print_results(results);
|
||||
free_results(results);
|
||||
free(path);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
return (1);
|
||||
remove_invalid_parentheses(argv[1]);
|
||||
return (0);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
Assignment name : rip
|
||||
Expected files : *.c *.h
|
||||
Allowed functions: puts, write
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Write a program that will take as argument a string containing only parenthesis.
|
||||
if the parenthesis are unbalanced (for example "())")
|
||||
your program shall remove the minimum number of parentheses for the expression to be balanced.
|
||||
By removing we mean replacing by spaces.
|
||||
You will then print all the solutions (can be more than one).
|
||||
|
||||
The order of the solutions is not important.
|
||||
|
||||
For example this should work:
|
||||
$> ./rip '(()' | cat -e
|
||||
()$
|
||||
( )$
|
||||
$> ./rip '((()()())())' | cat -e
|
||||
((()()())())$
|
||||
$> ./rip '()())()'| cat -e
|
||||
()() ()$
|
||||
()( )()$
|
||||
( ())()$
|
||||
$> ./rip '(()(()(' | cat -e
|
||||
(() ) $
|
||||
( )( ) $
|
||||
( ) () $
|
||||
()( ) $
|
||||
26
tsp/Makefile
26
tsp/Makefile
@ -1,26 +0,0 @@
|
||||
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
|
||||
@ -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! 🎉
|
||||
@ -1,8 +0,0 @@
|
||||
0, 0
|
||||
1, 0
|
||||
2, 0
|
||||
0, 1
|
||||
1, 1
|
||||
2, 1
|
||||
5, 2
|
||||
2, 2
|
||||
@ -1,64 +0,0 @@
|
||||
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
66
tsp/tsp.c
@ -1,66 +0,0 @@
|
||||
#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