-
-
Notifications
You must be signed in to change notification settings - Fork 342
Implemented the Subset Sum Problem algorithm in R. #171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
siriak
merged 6 commits into
TheAlgorithms:master
from
Sachinn-64:feat-subset-sum-clean
Oct 11, 2025
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7c7160e
Implemented the Subset Sum Problem algorithm in R.
Sachinn-64 e95b800
Update subset_sum.r
Sachinn-64 98428db
Update subset_sum.r
Sachinn-64 92a31c6
Update subset_sum.r
Sachinn-64 d2bf1d5
Update subset_sum.r
Sachinn-64 765a401
Merge branch 'master' into feat-subset-sum-clean
siriak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,288 @@ | ||
| # Subset Sum Problem | ||
| # | ||
| # The Subset Sum problem determines whether there exists a subset of a given set | ||
| # of positive integers that sums to a target value. This is a classic NP-complete | ||
| # problem solved using dynamic programming. | ||
| # | ||
| # Time Complexity: O(n * sum) where n = number of elements, sum = target sum | ||
| # Space Complexity: O(n * sum) for DP table, O(sum) for optimized version | ||
| # | ||
| # Applications: | ||
| # - Partition problems in computer science | ||
| # - Knapsack problem variations | ||
| # - Resource allocation and optimization | ||
| # - Cryptography and number theory | ||
| # - Game theory and decision making | ||
|
|
||
| # Basic DP solution for Subset Sum Problem | ||
| subset_sum <- function(arr, target) { | ||
| #' Check if there exists a subset that sums to the target value | ||
| #' @param arr: Numeric vector of positive integers | ||
| #' @param target: Target sum value | ||
| #' @return: Boolean indicating if subset exists, along with DP table | ||
|
|
||
| n <- length(arr) | ||
|
|
||
| # Handle edge cases | ||
| if (n == 0) { | ||
| return(list( | ||
| exists = (target == 0), | ||
| dp_table = matrix(FALSE, nrow = 1, ncol = 1), | ||
| subset = c() | ||
| )) | ||
| } | ||
|
|
||
| if (target == 0) { | ||
| return(list( | ||
| exists = TRUE, | ||
| dp_table = matrix(TRUE, nrow = n + 1, ncol = 1), | ||
| subset = c() | ||
| )) | ||
| } | ||
|
|
||
| # Create DP table: dp[i, j] = TRUE if sum j can be achieved using first i elements | ||
| dp <- matrix(FALSE, nrow = n + 1, ncol = target + 1) | ||
|
|
||
| # Base case: sum 0 can always be achieved with empty subset | ||
| for (i in 1:(n + 1)) { | ||
| dp[i, 1] <- TRUE | ||
| } | ||
|
|
||
| # Fill DP table | ||
| for (i in 2:(n + 1)) { | ||
| for (j in 1:(target + 1)) { | ||
| current_sum <- j - 1 # Convert to 0-based indexing | ||
|
|
||
| # Don't include current element | ||
| dp[i, j] <- dp[i - 1, j] | ||
|
|
||
| # Include current element (if it doesn't exceed current sum) | ||
| if (arr[i - 1] <= current_sum) { | ||
| dp[i, j] <- dp[i, j] || dp[i - 1, j - arr[i - 1]] | ||
| } | ||
| } | ||
| } | ||
|
|
||
| # Backtrack to find one possible subset | ||
| subset <- c() | ||
| if (dp[n + 1, target + 1]) { | ||
| i <- n + 1 | ||
| j <- target + 1 | ||
|
|
||
| while (i > 1 && j > 1) { | ||
| # If current sum was achieved without including arr[i-1] | ||
| if (dp[i - 1, j]) { | ||
| i <- i - 1 | ||
| } else { | ||
| # Current element was included | ||
| subset <- c(arr[i - 1], subset) | ||
| j <- j - arr[i - 1] | ||
| i <- i - 1 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return(list( | ||
| exists = dp[n + 1, target + 1], | ||
| dp_table = dp, | ||
| subset = subset | ||
| )) | ||
| } | ||
|
|
||
| # Space-optimized version using only 1D array | ||
| subset_sum_optimized <- function(arr, target) { | ||
| #' Space optimized subset sum using 1D array | ||
| #' @param arr: Numeric vector of positive integers | ||
| #' @param target: Target sum value | ||
| #' @return: Boolean indicating if subset exists | ||
|
|
||
| n <- length(arr) | ||
|
|
||
| if (n == 0) return(target == 0) | ||
| if (target == 0) return(TRUE) | ||
|
|
||
| dp <- rep(FALSE, target + 1) | ||
| dp[1] <- TRUE # sum 0 is always possible | ||
|
|
||
| for (i in 1:n) { | ||
| # Traverse from right to left to avoid overwriting needed values | ||
| for (j in target:1) { | ||
| if (arr[i] <= j) { | ||
| dp[j + 1] <- dp[j + 1] || dp[j - arr[i] + 1] | ||
| } | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Sachinn-64 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| return(dp[target + 1]) | ||
| } | ||
|
|
||
| # Function to find all subsets that sum to target | ||
| find_all_subsets <- function(arr, target) { | ||
| #' Find all subsets that sum to the target value | ||
| #' @param arr: Numeric vector of positive integers | ||
| #' @param target: Target sum value | ||
| #' @return: List of subsets (each subset is a numeric vector) that sum to target | ||
|
|
||
| n <- length(arr) | ||
| results <- list() | ||
|
|
||
| # Helper recursive function | ||
| find_subsets_rec <- function(idx, current_subset, current_sum) { | ||
| if (current_sum == target) { | ||
| results <<- c(results, list(current_subset)) | ||
| return() | ||
| } | ||
| if (idx > n || current_sum > target) { | ||
| return() | ||
| } | ||
| # Include arr[idx] | ||
| find_subsets_rec(idx + 1, c(current_subset, arr[idx]), current_sum + arr[idx]) | ||
| # Exclude arr[idx] | ||
| find_subsets_rec(idx + 1, current_subset, current_sum) | ||
| } | ||
|
|
||
| find_subsets_rec(1, c(), 0) | ||
| return(results) | ||
| } | ||
|
|
||
| # Helper function to print DP table | ||
| print_subset_sum_dp <- function(dp_table, arr, target) { | ||
| cat("DP Table for Subset Sum Problem:\n") | ||
| cat("Array:", paste(arr, collapse = ", "), "\n") | ||
| cat("Target Sum:", target, "\n\n") | ||
|
|
||
| # Print column headers (sums) | ||
| cat(" ") | ||
| cat(paste(sprintf("%4d", 0:target), collapse = " ")) | ||
| cat("\n") | ||
| cat(paste(rep("-", 8 + 5 * (target + 1)), collapse = ""), "\n") | ||
|
|
||
| for (i in 1:nrow(dp_table)) { | ||
| if (i == 1) { | ||
| cat("Empty | ") | ||
| } else { | ||
| cat(sprintf("Elem%2d| ", i - 1)) | ||
| } | ||
|
|
||
| for (j in 1:ncol(dp_table)) { | ||
| cat(sprintf("%4s", ifelse(dp_table[i, j], " T", " F"))) | ||
| } | ||
| cat("\n") | ||
| } | ||
| cat("\n") | ||
| } | ||
|
|
||
| # =========================== | ||
| # Example Usage & Testing | ||
| # =========================== | ||
| cat("=== Subset Sum Problem (Dynamic Programming) ===\n\n") | ||
|
|
||
| # Test 1: Basic Example | ||
| arr1 <- c(3, 34, 4, 12, 5, 2) | ||
| target1 <- 9 | ||
| cat("Test 1: Basic Example\n") | ||
| cat("Array:", paste(arr1, collapse = ", "), "\n") | ||
| cat("Target Sum:", target1, "\n\n") | ||
|
|
||
| result1 <- subset_sum(arr1, target1) | ||
| print_subset_sum_dp(result1$dp_table, arr1, target1) | ||
| cat("Subset exists:", result1$exists, "\n") | ||
| if (result1$exists) { | ||
| cat("One possible subset:", paste(result1$subset, collapse = ", "), "\n") | ||
| cat("Sum verification:", sum(result1$subset), "\n") | ||
| } | ||
| cat("\n") | ||
|
|
||
| # Test 2: Optimized Version | ||
| cat("Test 2: Space Optimized Version\n") | ||
| exists_opt <- subset_sum_optimized(arr1, target1) | ||
| cat("Subset exists (Optimized):", exists_opt, "\n") | ||
| cat("Verification: Both methods match:", result1$exists == exists_opt, "\n\n") | ||
|
|
||
| # Test 3: No Solution Case | ||
| cat("Test 3: No Solution Case\n") | ||
| arr3 <- c(3, 34, 4, 12, 5, 2) | ||
| target3 <- 30 | ||
| cat("Array:", paste(arr3, collapse = ", "), "\n") | ||
| cat("Target Sum:", target3, "\n") | ||
|
|
||
| result3 <- subset_sum(arr3, target3) | ||
| cat("Subset exists:", result3$exists, "\n\n") | ||
|
|
||
| # Test 4: Multiple Solutions | ||
| cat("Test 4: Multiple Solutions\n") | ||
| arr4 <- c(1, 2, 3, 4, 5) | ||
| target4 <- 6 | ||
| cat("Array:", paste(arr4, collapse = ", "), "\n") | ||
| cat("Target Sum:", target4, "\n") | ||
|
|
||
| result4 <- subset_sum(arr4, target4) | ||
| cat("Subset exists:", result4$exists, "\n") | ||
| if (result4$exists) { | ||
| cat("One possible subset:", paste(result4$subset, collapse = ", "), "\n") | ||
|
|
||
| # Find all possible subsets | ||
| all_subsets <- find_all_subsets(arr4, target4) | ||
Sachinn-64 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cat("Total number of subsets:", length(all_subsets), "\n") | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| for (i in seq_along(all_subsets)) { | ||
| cat("Subset", i, ":", paste(all_subsets[[i]], collapse = ", "), | ||
| "(sum =", sum(all_subsets[[i]]), ")\n") | ||
| } | ||
| } | ||
| cat("\n") | ||
|
|
||
| # Test 5: Edge Cases | ||
| cat("Test 5: Edge Cases\n") | ||
| cat("Empty array, target 0:", subset_sum(c(), 0)$exists, "\n") | ||
| cat("Empty array, target 5:", subset_sum(c(), 5)$exists, "\n") | ||
| cat("Array [1,2,3], target 0:", subset_sum(c(1, 2, 3), 0)$exists, "\n") | ||
| cat("Array [5], target 5:", subset_sum(c(5), 5)$exists, "\n") | ||
| cat("Array [5], target 3:", subset_sum(c(5), 3)$exists, "\n\n") | ||
|
|
||
| # Test 6: Larger Dataset | ||
| cat("Test 6: Larger Dataset (n=15)\n") | ||
| set.seed(42) | ||
| arr_large <- sample(1:20, 15) | ||
| target_large <- 50 | ||
| cat("Array:", paste(arr_large, collapse = ", "), "\n") | ||
| cat("Target Sum:", target_large, "\n") | ||
|
|
||
| start_time <- Sys.time() | ||
| result_large <- subset_sum(arr_large, target_large) | ||
| dp_time <- as.numeric(Sys.time() - start_time, units = "secs") | ||
|
|
||
| start_time <- Sys.time() | ||
| exists_large_opt <- subset_sum_optimized(arr_large, target_large) | ||
| opt_time <- as.numeric(Sys.time() - start_time, units = "secs") | ||
|
|
||
| cat("Subset exists:", result_large$exists, "\n") | ||
| cat("DP method time:", sprintf("%.4f sec", dp_time), "\n") | ||
| cat("Optimized method time:", sprintf("%.4f sec", opt_time), "\n") | ||
| cat("Results match:", result_large$exists == exists_large_opt, "\n") | ||
|
|
||
| if (result_large$exists) { | ||
| cat("One possible subset:", paste(result_large$subset, collapse = ", "), "\n") | ||
| cat("Sum verification:", sum(result_large$subset), "\n") | ||
| } | ||
| cat("\n") | ||
|
|
||
| # Test 7: Real-world Example - Budget Allocation | ||
| cat("Test 7: Real-world Example - Budget Allocation\n") | ||
| project_costs <- c(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) | ||
| budget <- 150 | ||
| cat("Project costs:", paste(project_costs, collapse = ", "), "\n") | ||
| cat("Available budget:", budget, "\n") | ||
|
|
||
| budget_result <- subset_sum(project_costs, budget) | ||
| cat("Exact budget allocation possible:", budget_result$exists, "\n") | ||
|
|
||
| if (budget_result$exists) { | ||
| selected_projects <- budget_result$subset | ||
| cat("Selected projects (costs):", paste(selected_projects, collapse = ", "), "\n") | ||
| cat("Total cost:", sum(selected_projects), "\n") | ||
| cat("Remaining budget:", budget - sum(selected_projects), "\n") | ||
| } else { | ||
| # Find closest possible sum (≤ budget) in a single pass | ||
| closest_sum <- max_subset_sum_leq(project_costs, budget) | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cat("Closest possible sum:", closest_sum, "\n") | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.