From 393bcc3028bb52f01919925b221e33898eb3b4cb Mon Sep 17 00:00:00 2001 From: Rui Ribeiro <42305006+ruiribeiro04@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:16:23 +0100 Subject: [PATCH] added powerset --- powerset/Makefile | 83 ++++++++++++++++++++ powerset/README.md | 175 +++++++++++++++++++++++++++++++++++++++++++ powerset/powerset.c | 85 +++++++++++++++++++++ powerset/powerset.h | 24 ++++++ powerset/subject.txt | 65 ++++++++++++++++ 5 files changed, 432 insertions(+) create mode 100644 powerset/Makefile create mode 100644 powerset/README.md create mode 100644 powerset/powerset.c create mode 100644 powerset/powerset.h create mode 100644 powerset/subject.txt diff --git a/powerset/Makefile b/powerset/Makefile new file mode 100644 index 0000000..1988e05 --- /dev/null +++ b/powerset/Makefile @@ -0,0 +1,83 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: ruiferna +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2025/09/22 00:00:00 by ruiferna #+# #+# # +# Updated: 2025/09/22 17:15:15 by ruiferna ### ########.fr # +# # +# **************************************************************************** # + +# 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 \ No newline at end of file diff --git a/powerset/README.md b/powerset/README.md new file mode 100644 index 0000000..ef51e34 --- /dev/null +++ b/powerset/README.md @@ -0,0 +1,175 @@ +# 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?* 🤖✨ \ No newline at end of file diff --git a/powerset/powerset.c b/powerset/powerset.c new file mode 100644 index 0000000..dc869ff --- /dev/null +++ b/powerset/powerset.c @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* powerset.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ruiferna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/09/22 00:00:00 by ruiferna #+# #+# */ +/* Updated: 2025/09/22 17:12:50 by ruiferna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#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); +} \ No newline at end of file diff --git a/powerset/powerset.h b/powerset/powerset.h new file mode 100644 index 0000000..d512a11 --- /dev/null +++ b/powerset/powerset.h @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* powerset.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ruiferna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/09/22 00:00:00 by ruiferna #+# #+# */ +/* Updated: 2025/09/22 17:12:51 by ruiferna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef POWERSET_H +# define POWERSET_H + +# include +# include +# include + +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 \ No newline at end of file diff --git a/powerset/subject.txt b/powerset/subject.txt new file mode 100644 index 0000000..4e2911a --- /dev/null +++ b/powerset/subject.txt @@ -0,0 +1,65 @@ +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 +... \ No newline at end of file