子集总和

Description:

描述:

In this article, we are going to see how to solve the subset sum problem which has been featured in many interview rounds like Amazon, Microsoft?

在本文中,我们将看到如何解决在许多采访回合(如亚马逊,微软)中出现的子集和问题

Problem statement:

问题陈述:

Given an array of size n and a sum K, determine whether any subset is possible with that sum or not. Print "yes" if there is any subset present else print "no".

给定大小为n的数组和总和K ,确定使用该总和是否可能存在任何子集。 如果存在任何子集,请打印“是” ,否则请打印“否”

    Input & output:
    In the first line the input will be n and K, space separated.
    The next line contains the array elements

    Output will be "yes" or "no"

Example with explanation:

带有说明的示例:

Example 1:

范例1:

    Input:

    The array size be: 5
    The sum be: 11
    The Elements be: 5 6 7 3 9

    Output:
    Yes

    Explanation:
    5 & 6 sums to 11. Thus the subset can be [5, 6] and output will be "yes".

Example 2:

范例2:

    Input:

    The array size be: 5
    The sum be: 11
    The Elements be: 5 6 7 3 9

    Output:
    Yes

    Explanation:
    5 & 6 sums to 11. Thus the subset can be [5, 6] and output will be "yes".

Solution Approach:

解决方法:

Of course the naïve solution would be to generate all possible subsets and check their sum equals to K or not. But it would of course be computationally exponential to generate all possible subsets.

当然,天真的解决方案是生成所有可能的子集,并检查它们的总和是否等于K。 但是,生成所有可能的子集在计算上当然是指数的。

To do so, the recursion would be:

为此,递归将是:

For nth element the cases are:

对于 n 元素,情况为:

  1. Consider the nth element as part of solution subset and recur for n-1 elements for obtaining sum (K-arr[n]).

    n 元素视为解决方案子集的一部分,然后对n-1个元素递归以获取总和(K-arr [n])。

  2. Don't consider nth element as part of solution subset and recur for n-1 elements for obtaining sum (K).

    不要将 n 元素视为解决方案子集的一部分,而是递归获取n-1个元素以获得和(K)。

So, the recursion function can be written as:

因此,递归函数可以写为:

    f(n,K)=f(n-1,K) | f(n-1,K-arr[n-1])

Where,

哪里,

    f(n,K)= value for problem with array size n and sum K which can be either true or false

Now base case would be,

现在的基本情况是


   
   
f(0,0) = true f(0,i) = false for 1 ≤ i ≤K f(i,0) = true 1 ≤ i ≤ n

Here comes the concept of sub problem. Initially the problem is for size n and sum K. Then it gets reduced to {size (n-1) and sum K} or {size (n-1) and (sum K-arr[n-1])}

这是子问题的概念。 最初,问题是大小为n和K的问题。然后,问题变为{大小(n-1)和K为总和}或{大小(n-1)和(sum K-arr [n-1])}

So if you draw the recursion tree there will be many such sub-problem which will be overlapping ones. That means we will re-compute same sub-problems again and again. That’s why we need to store the value of sub-problems and use dynamic programming.

因此,如果您绘制递归树,将会有很多这样的子问题,它们将是重叠的。 这意味着我们将一次又一次地重新计算相同的子问题。 这就是为什么我们需要存储子问题的值并使用动态编程的原因。

Converting to dynamic programming:

转换为动态编程:

    1)  Initialize  dp[n+1][sum+1] which is a Boolean table to false
    2)  Convert the base cases for recursion
        for i=1 to sum
            dp[0][i]=false;
        for i=0 to n
            dp[i][0]=true;
    3)  Build the table as per the recursion formula.
        for i=1 to sum
            for j=1 to n
                //if sub-sum i>jth element then only we can take that
                if(i>=arr[j-1])   
                    //consider both case mentioned in solution approach
                    dp[j][i]=dp[j-1][i] | dp[j-1][i-arr[j-1]];   
                else                       // don't take jth element
                    dp[j][i]=dp[j-1][i];

                if(i==sum)
                    if(dp[j][i]){
                        return true;
                End If
            end for
        end for

    4)  If not returned from the loop  
            return false;

C++ Implementation:

C ++实现:

#include <bits/stdc++.h>
using namespace std;

bool subsetSum(vector<int> arr, int n, int sum)
{
    //DP matrix
    bool dp[n + 1][sum + 1];

    memset(dp, false, sizeof(dp));

    //base case
    for (int i = 1; i <= sum; i++)
        dp[0][i] = false;
	
    for (int i = 0; i <= n; i++)
        dp[i][0] = true;
	
    //build the table
    for (int i = 1; i <= sum; i++) {
        for (int j = 1; j <= n; j++) {
            if (i >= arr[j - 1])
                dp[j][i] = dp[j - 1][i] | dp[j - 1][i - arr[j - 1]];
            else
                dp[j][i] = dp[j - 1][i];

            if (i == sum) {
                if (dp[j][i]) {

                    return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    int t, n, k, item;
	
    cout << "Enter array length,n\n";
    cin >> n;
	
    cout << "Enter sum,K\n";
    cin >> k;
	
    cout << "Enter elements\n";
    vector<int> a;
    for (int j = 0; j < n; j++) {
        scanf("%d", &item);
        a.push_back(item);
    }

    if (subsetSum(a, n, k))
        cout << "yes\n";
    else
        cout << "no\n";

    return 0;
}

Output

输出量

RUN 1:
Enter array length,n
5
Enter sum,K
11
Enter elements
5 6 7 3 9
yes

RUN 2:
Enter array length,n
5
Enter sum,K
22
Enter elements
5 6 7 3 9
yes


翻译自: https://www.includehelp.com/icp/subset-sum.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值