Suma Combinacional

Dada una array de enteros positivos arr[] y una suma x , encuentra todas las combinaciones únicas en arr[] donde la suma es igual a x. Se puede elegir el mismo número repetido de arr[] un número ilimitado de veces. Los elementos de una combinación (a1, a2, …, ak) deben imprimirse en orden no descendente. (es decir, a1 <= a2 <= … <= ak). 
Las combinaciones en sí deben clasificarse en orden ascendente, es decir, la combinación con el primer elemento más pequeño debe imprimirse primero. Si no hay combinación posible se imprime “Vacío” (sin comillas).

Ejemplos: 

Input : arr[] = 2, 4, 6, 8 
            x = 8
Output : [2, 2, 2, 2]
         [2, 2, 4]
         [2, 6]
         [4, 4]
         [8]

Dado que el problema es obtener todos los resultados posibles, no el mejor o la cantidad de resultados, no necesitamos considerar DP (programación dinámica), se necesita recursividad para manejarlo.

Deberíamos usar el siguiente algoritmo. 

1. Sort the array(non-decreasing).
2. First remove all the duplicates from array.
3. Then use recursion and backtracking to solve 
   the problem.
   (A) If at any time sub-problem sum == 0 then 
       add that array to the result (vector of 
       vectors).
   (B) Else if sum is negative then ignore that 
       sub-problem.
   (C) Else insert the present index in that 
       array to the current vector and call 
       the function with sum = sum-ar[index] and
       index = index, then pop that element from 
       current index (backtrack) and call the 
       function with sum = sum and index = index+1

A continuación se muestra la implementación en C++ de los pasos anteriores.

C++

// C++ program to find all combinations that
// sum to a given value
#include <bits/stdc++.h>
using namespace std;
 
// Print all members of ar[] that have given
void findNumbers(vector<int>& ar, int sum,
                 vector<vector<int> >& res, vector<int>& r,
                 int i)
{
    // if we get exact answer
    if (sum == 0) {
        res.push_back(r);
        return;
    }
 
    // Recur for all remaining elements that
    // have value smaller than sum.
    while (i < ar.size() && sum - ar[i] >= 0) {
 
        // Till every element in the array starting
        // from i which can contribute to the sum
        r.push_back(ar[i]); // add them to list
 
        // recursive call for next numbers
        findNumbers(ar, sum - ar[i], res, r, i);
        i++;
 
        // Remove number from list (backtracking)
        r.pop_back();
    }
}
 
// Returns all combinations
// of ar[] that have given
// sum.
vector<vector<int> > combinationSum(vector<int>& ar,
                                    int sum)
{
    // sort input array
    sort(ar.begin(), ar.end());
 
    // remove duplicates
    ar.erase(unique(ar.begin(), ar.end()), ar.end());
 
    vector<int> r;
    vector<vector<int> > res;
    findNumbers(ar, sum, res, r, 0);
 
    return res;
}
 
// Driver code
int main()
{
    vector<int> ar;
    ar.push_back(2);
    ar.push_back(4);
    ar.push_back(6);
    ar.push_back(8);
    int n = ar.size();
 
    int sum = 8; // set value of sum
    vector<vector<int> > res = combinationSum(ar, sum);
 
    // If result is empty, then
    if (res.size() == 0) {
        cout << "Empty";
        return 0;
    }
 
    // Print all combinations stored in res.
    for (int i = 0; i < res.size(); i++) {
        if (res[i].size() > 0) {
            cout << " ( ";
            for (int j = 0; j < res[i].size(); j++)
                cout << res[i][j] << " ";
            cout << ")";
        }
    }
  return 0;
}

Java

// Java program to find all combinations that
// sum to a given value
import java.io.*;
import java.util.*;
 
class GFG {
 
    static ArrayList<ArrayList<Integer> >
    combinationSum(ArrayList<Integer> arr, int sum)
    {
        ArrayList<ArrayList<Integer> > ans
            = new ArrayList<>();
        ArrayList<Integer> temp = new ArrayList<>();
 
        // first do hashing since hashset does not always
        // sort
        //  removing the duplicates using HashSet and
        // Sorting the arrayList
 
        Set<Integer> set = new HashSet<>(arr);
        arr.clear();
        arr.addAll(set);
        Collections.sort(arr);
 
        findNumbers(ans, arr, sum, 0, temp);
        return ans;
    }
 
    static void
    findNumbers(ArrayList<ArrayList<Integer> > ans,
                ArrayList<Integer> arr, int sum, int index,
                ArrayList<Integer> temp)
    {
 
        if (sum == 0) {
 
            // Adding deep copy of list to ans
 
            ans.add(new ArrayList<>(temp));
            return;
        }
 
        for (int i = index; i < arr.size(); i++) {
 
            // checking that sum does not become negative
 
            if ((sum - arr.get(i)) >= 0) {
 
                // adding element which can contribute to
                // sum
 
                temp.add(arr.get(i));
 
                findNumbers(ans, arr, sum - arr.get(i), i,
                            temp);
 
                // removing element from list (backtracking)
                temp.remove(arr.get(i));
            }
        }
    }
 
    // Driver Code
 
    public static void main(String[] args)
    {
        ArrayList<Integer> arr = new ArrayList<>();
 
        arr.add(2);
        arr.add(4);
        arr.add(6);
        arr.add(8);
 
        int sum = 8;
 
        ArrayList<ArrayList<Integer> > ans
            = combinationSum(arr, sum);
 
        // If result is empty, then
        if (ans.size() == 0) {
            System.out.println("Empty");
            return;
        }
 
        // print all combinations stored in ans
 
        for (int i = 0; i < ans.size(); i++) {
 
            System.out.print("(");
            for (int j = 0; j < ans.get(i).size(); j++) {
                System.out.print(ans.get(i).get(j) + " ");
            }
            System.out.print(") ");
        }
    }
}

Python3

# Python3 program to find all combinations that
# sum to a given value
 
def combinationSum(arr, sum):
    ans = []
    temp = []
 
    # first do hashing nothing but set{}
    # since set does not always sort
    # removing the duplicates using Set and
    # Sorting the List
    arr = sorted(list(set(arr)))
    findNumbers(ans, arr, temp, sum, 0)
    return ans
 
def findNumbers(ans, arr, temp, sum, index):
     
    if(sum == 0):
         
        # Adding deep copy of list to ans
        ans.append(list(temp))
        return
       
    # Iterate from index to len(arr) - 1
    for i in range(index, len(arr)):
 
        # checking that sum does not become negative
        if(sum - arr[i]) >= 0:
 
            # adding element which can contribute to
            # sum
            temp.append(arr[i])
            findNumbers(ans, arr, temp, sum-arr[i], i)
 
            # removing element from list (backtracking)
            temp.remove(arr[i])
 
 
# Driver Code
arr = [2, 4, 6, 8]
sum = 8
ans = combinationSum(arr, sum)
 
# If result is empty, then
if len(ans) <= 0:
    print("empty")
     
# print all combinations stored in ans
for i in range(len(ans)):
 
    print("(", end=' ')
    for j in range(len(ans[i])):
        print(str(ans[i][j])+" ", end=' ')
    print(")", end=' ')
 
 
# This Code Is Contributed by Rakesh(vijayarigela09)

C#

// C# program for the above approach
using System;
using System.Collections.Generic;
using System.Collections;
 
class GFG {
 
    static List<List<int> >
    combinationSum(List<int> arr, int sum)
    {
        List<List<int> > ans
            = new List<List<int> >();
        List<int> temp = new List<int>();
 
        // first do hashing since hashset does not always
        // sort
        //  removing the duplicates using HashSet and
        // Sorting the List
 
        HashSet<int> set = new HashSet<int>(arr);
        arr.Clear();
        arr.AddRange(set);
        arr.Sort();
 
        findNumbers(ans, arr, sum, 0, temp);
        return ans;
    }
 
    static void
    findNumbers(List<List<int> > ans,
                List<int> arr, int sum, int index,
                List<int> temp)
    {
 
        if (sum == 0) {
 
            // Adding deep copy of list to ans
 
            ans.Add(new List<int>(temp));
            return;
        }
 
        for (int i = index; i < arr.Count; i++) {
 
            // checking that sum does not become negative
 
            if ((sum - arr[i]) >= 0) {
 
                // Adding element which can contribute to
                // sum
 
                temp.Add(arr[i]);
 
                findNumbers(ans, arr, sum - arr[i], i,
                            temp);
 
                // removing element from list (backtracking)
                temp.Remove(arr[i]);
            }
        }
    }
 
    // Driver Code
 
    public static void Main()
    {
        List<int> arr = new List<int>();
         
        arr.Add(2);
        arr.Add(4);
        arr.Add(6);
        arr.Add(8);
 
        int sum = 8;
 
        List<List<int> > ans
            = combinationSum(arr, sum);
 
        // If result is empty, then
        if (ans.Count == 0) {
            Console.WriteLine("Empty");
            return;
        }
 
        // print all combinations stored in ans
 
        for (int i = 0; i < ans.Count; i++) {
 
            Console.Write("(");
            for (int j = 0; j < ans[i].Count; j++) {
                Console.Write(ans[i][j] + " ");
            }
            Console.Write(") ");
        }
    }
}
 
// This code is contributed by ShubhamSingh10

Javascript

<script>
// Javascript program to find all combinations that
// sum to a given value
 
function combinationSum(arr, sum) {
    let ans = new Array();
    let temp = new Array();
 
    // first do hashing since hashset does not always
    // sort
    //  removing the duplicates using HashSet and
    // Sorting the arrayList
 
    let set = new Set([...arr]);
    arr = [...set];
    arr.sort()
 
    findNumbers(ans, arr, sum, 0, temp);
    return ans;
}
 
function findNumbers(ans, arr, sum, index, temp) {
 
    if (sum == 0) {
 
        // pushing deep copy of list to ans
 
        ans.push([...temp]);
        return;
    }
 
    for (let i = index; i < arr.length; i++) {
 
        // checking that sum does not become negative
 
        if ((sum - arr[i]) >= 0) {
 
            // pushing element which can contribute to
            // sum
 
            temp.push(arr[i]);
 
            findNumbers(ans, arr, sum - arr[i], i, temp);
 
            // removing element from list (backtracking)
            temp.splice(temp.indexOf(arr[i]), 1);
        }
    }
}
 
// Driver Code
 
 
let arr = []
 
arr.push(2);
arr.push(4);
arr.push(6);
arr.push(8);
 
let sum = 8;
 
let ans = combinationSum(arr, sum);
 
// If result is empty, then
if (ans.length == 0) {
    document.write("Empty");
}
 
// print all combinations stored in ans
for (let i = 0; i < ans.length; i++) {
 
    document.write("(");
    for (let j = 0; j < ans[i].length; j++) {
        document.write(" ", ans[i][j] + " ");
    }
    document.write(") ");
}
 
// This code is contributed by saurabh_jaiswal.
</script>
Producción

 ( 2 2 2 2 ) ( 2 2 4 ) ( 2 6 ) ( 4 4 ) ( 8 )

Complejidad de tiempo: O(n 2 ), donde n es el tamaño de la array.

Espacio Auxiliar: O(n 2 )

Este artículo es una contribución de Aditya Nihal Kumar Singh . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *