📜  总和为零的子集数

📅  最后修改于: 2021-04-21 21:24:58             🧑  作者: Mango

给定一个由整数组成的数组“ arr”,任务是找到子集的数量,以使它们的总和等于零。空子集也应予以考虑。

例子:

一种简单的方法是递归生成所有可能的子集,并计算总和等于0的子集数。此方法的时间复杂度为O(2 ^ n)。

更好的方法是使用动态编程
让我们假设直到索引i-1为止我们选择的所有元素的总和是S。因此,从索引“ i”开始,我们必须找到总和等于-S的子数组{i,N-1}的子集数。
让我们定义dp [i] [S]。这意味着“ arr”的子数组{i,N-1}的子集的个数之和等于“ -S”。
如果我们处于第i个索引,则有两个选择,即将其包括在总和中或保留它。
因此,所需的递归关系变为

下面是上述方法的实现:

C++
#include 
#define maxSum 100
#define arrSize 51
using namespace std;
  
// variable to store
// states of dp
int dp[arrSize][maxSum];
bool visit[arrSize][maxSum];
  
// To find the number of subsets with sum equal to 0
// Since S can be negative, we will maxSum
// to it to make it positive
int SubsetCnt(int i, int s, int arr[], int n)
{
    // Base cases
    if (i == n) {
        if (s == 0)
            return 1;
        else
            return 0;
    }
  
    // Returns the value if a state is already solved
    if (visit[i][s + maxSum])
        return dp[i][s + maxSum];
  
    // If the state is not visited, then continue
    visit[i][s + maxSum] = 1;
  
    // Recurrence relation
    dp[i][s + maxSum] = SubsetCnt(i + 1, s + arr[i], arr, n)
                        + SubsetCnt(i + 1, s, arr, n);
  
    // Returning the value
    return dp[i][s + maxSum];
}
  
// Driver function
int main()
{
    int arr[] = { 2, 2, 2, -4, -4 };
    int n = sizeof(arr) / sizeof(int);
  
    cout << SubsetCnt(0, 0, arr, n);
}


Java
// Java implementation of above approach
class GFG 
{
  
    static int maxSum = 100;
    static int arrSize = 51;
  
    // variable to store
    // states of dp
    static int[][] dp = new int[arrSize][maxSum];
    static boolean[][] visit = new boolean[arrSize][maxSum];
  
    // To find the number of subsets with sum equal to 0
    // Since S can be negative, we will maxSum
    // to it to make it positive
    static int SubsetCnt(int i, int s, int arr[], int n)
    {
        // Base cases
        if (i == n) 
        {
            if (s == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
  
        // Returns the value if a state is already solved
        if (visit[i][s + arrSize]) 
        {
            return dp[i][s + arrSize];
        }
  
        // If the state is not visited, then continue
        visit[i][s + arrSize] = true;
  
        // Recurrence relation
        dp[i][s + arrSize] = SubsetCnt(i + 1, s + arr[i], arr, n)
                + SubsetCnt(i + 1, s, arr, n);
  
        // Returning the value
        return dp[i][s + arrSize];
    }
  
    // Driver function
    public static void main(String[] args)
    {
        int arr[] = {2, 2, 2, -4, -4};
        int n = arr.length;
  
        System.out.println(SubsetCnt(0, 0, arr, n));
    }
}
  
/* This code contributed by PrinciRaj1992 */


Python3
# Python3 implementation of above approach 
import numpy as np
  
maxSum = 100
arrSize = 51
  
# variable to store 
# states of dp 
dp = np.zeros((arrSize, maxSum)); 
visit = np.zeros((arrSize, maxSum)); 
  
# To find the number of subsets 
# with sum equal to 0.
# Since S can be negative, 
# we will maxSum to it
# to make it positive 
def SubsetCnt(i, s, arr, n) :
      
    # Base cases 
    if (i == n) :
        if (s == 0) :
            return 1; 
        else :
            return 0; 
      
    # Returns the value 
    # if a state is already solved 
    if (visit[i][s + arrSize]) :
        return dp[i][s + arrSize]; 
  
    # If the state is not visited, 
    # then continue 
    visit[i][s + arrSize] = 1; 
  
    # Recurrence relation 
    dp[i][s + arrSize ] = (SubsetCnt(i + 1, s + arr[i], arr, n) + 
                           SubsetCnt(i + 1, s, arr, n)); 
  
    # Returning the value 
    return dp[i][s + arrSize]; 
  
# Driver Code
if __name__ == "__main__" : 
  
    arr = [ 2, 2, 2, -4, -4 ]; 
    n = len(arr); 
  
    print(SubsetCnt(0, 0, arr, n)); 
  
# This code is contributed by AnkitRai01


C#
// C# implementation of above approach
using System;
  
class GFG 
{
  
    static int maxSum = 100;
    static int arrSize = 51;
  
    // variable to store
    // states of dp
    static int [,]dp = new int[arrSize, maxSum];
    static bool [,]visit = new bool[arrSize, maxSum];
  
    // To find the number of subsets with sum equal to 0
    // Since S can be negative, we will maxSum
    // to it to make it positive
    static int SubsetCnt(int i, int s, int []arr, int n)
    {
        // Base cases
        if (i == n) 
        {
            if (s == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
  
        // Returns the value if a state is already solved
        if (visit[i, s + arrSize]) 
        {
            return dp[i, s + arrSize];
        }
  
        // If the state is not visited, then continue
        visit[i, s + arrSize] = true;
  
        // Recurrence relation
        dp[i, s + arrSize] = SubsetCnt(i + 1, s + arr[i], arr, n)
                + SubsetCnt(i + 1, s, arr, n);
  
        // Returning the value
        return dp[i,s + arrSize];
    }
  
    // Driver code
    public static void Main()
    {
        int []arr = {2, 2, 2, -4, -4};
        int n = arr.Length;
  
        Console.WriteLine(SubsetCnt(0, 0, arr, n));
    }
}
  
// This code contributed by anuj_67..


输出:
7

时间复杂度: O(n * S),其中n是数组中元素的数量,S是所有元素的总和。