📜  组合总和

📅  最后修改于: 2021-05-24 21:06:52             🧑  作者: Mango

给定正整数数组arr []x的总和,请在arr []中找到总和等于x的所有唯一组合。可以从arr []无限次数中选择相同的重复数。组合中的元素(a1,a2,…,ak)必须以降序打印。 (即a1 <= a2 <=…<= ak)。
组合本身必须按升序排序,即,应首先打印具有最小第一元素的组合。如果没有可能的组合,则打印“空”(不带引号)。

例子:

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

由于问题在于获取所有可能的结果,而不是最佳结果或数量,因此我们不需要考虑DP(动态编程),因此需要递归来处理它。

我们应该使用以下算法。

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 array in that 
       index 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

以下是上述步骤的C++实现。

C++
// C++ program to find all combinations that
// sum to a given value
#include 
using namespace std;
 
// Print all members of ar[] that have given
void findNumbers(vector& ar, int sum,
                 vector >& res, vector& 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
 
        // recur 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 > combinationSum(vector& ar,
                                    int sum)
{
    // sort input array
    sort(ar.begin(), ar.end());
 
    // remove duplicates
    ar.erase(unique(ar.begin(), ar.end()), ar.end());
 
    vector r;
    vector > res;
    findNumbers(ar, sum, res, r, 0);
 
    return res;
}
 
// Driver code
int main()
{
    vector 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 > res = combinationSum(ar, sum);
 
    // If result is empty, then
    if (res.size() == 0) {
        cout << "Emptyn";
        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 << ")";
        }
    }
}


Java
// Java program to find all combinations that
// sum to a given value
import java.io.*;
import java.util.*;
 
class GFG {
 
    static ArrayList >
    combinationSum(ArrayList arr, int sum)
    {
        ArrayList > ans
            = new ArrayList<>();
        ArrayList temp = new ArrayList<>();
 
        // first do hashing since hashset does not always
        // sort
        //  removing the duplicates using HashSet and
        // Sorting the arrayList
 
        Set set = new HashSet<>(arr);
        arr.clear();
        arr.addAll(set);
        Collections.sort(arr);
 
        findNumbers(ans, arr, sum, 0, temp);
        return ans;
    }
 
    static void
    findNumbers(ArrayList > ans,
                ArrayList arr, int sum, int index,
                ArrayList 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 arr = new ArrayList<>();
 
        arr.add(2);
        arr.add(4);
        arr.add(6);
        arr.add(8);
 
        int sum = 8;
 
        ArrayList > 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)


输出
( 2 2 2 2 ) ( 2 2 4 ) ( 2 6 ) ( 4 4 ) ( 8 )