📜  总和最接近零的子集

📅  最后修改于: 2021-04-27 09:13:08             🧑  作者: Mango

给定一个由整数组成的数组“ arr”,任务是找到非空子集,使其总和最接近零,即零和之和之间的绝对差最小。

例子:

一种简单的方法是递归生成所有可能的子集,并找到总和最接近零的子集。这种方法的时间复杂度将是O(2 ^ n)。

一种更好的方法是在伪多项式时间复杂度中使用动态规划
让我们假设直到索引i-1为止我们选择的所有元素的总和是S。因此,从索引“ i”开始,我们必须找到一个总和最接近-S的子集。
首先定义dp [i] [S]。这意味着数组“ arr”的子数组{i,N-1}的子集的总和最接近“ -S”。

现在,我们可以在当前总和中包括“ i”或保留它。因此,我们有两种可能的方法。如果我们包含“ i”,则当前总和将更新为S + arr [i],我们将求解索引“ i + 1”,即dp [i + 1] [S + arr [i]],否则我们将求解直接索引“ i + 1”。因此,所需的递归关系将是。

下面是上述方法的实现:

C++
#include 
using namespace std;
  
#define arrSize 51
#define maxSum 201
#define MAX 100
#define inf 999999
   
// Variable to store states of dp
int dp[arrSize][maxSum];
bool visit[arrSize][maxSum];
   
// Function to return the number closer to integer s
int RetClose(int a, int b, int s)
{
    if (abs(a - s) < abs(b - s))
        return a;
    else
        return b;
}
   
// To find the sum closest to zero
// Since sum can be negative, we will add MAX
// to it to make it positive
int MinDiff(int i, int sum, int arr[], int n)
{
   
    // Base cases
    if (i == n)
        return 0;
    // Checks if a state is already solved
    if (visit[i][sum + MAX])
        return dp[i][sum + MAX];
    visit[i][sum + MAX] = 1;
   
    // Recurrence relation
    dp[i][sum + MAX] =  RetClose(arr[i] +
                        MinDiff(i + 1, sum + arr[i], arr, n),
                        MinDiff(i + 1, sum, arr, n), -1 * sum);
   
    // Returning the value
    return dp[i][sum + MAX];
}
  
// Function to calculate the closest sum value
void FindClose(int arr[],int n)
{
    int ans=inf;
  
    // Calculate the Closest value for every
    // subarray arr[i-1:n]
    for (int i = 1; i <= n; i++)
        ans = RetClose(arr[i - 1] +
                MinDiff(i, arr[i - 1], arr, n), ans, 0);
  
    cout<


Java
// Java Program for above approach
import java.io.*;
  
class GFG 
{
      
static int arrSize = 51;
static int maxSum = 201;
static int MAX = 100;
static int inf = 999999;
  
// Variable to store states of dp
static int dp[][] = new int [arrSize][maxSum];
static int visit[][] = new int [arrSize][maxSum];
  
// Function to return the number 
// closer to integer s
static int RetClose(int a, int b, int s)
{
    if (Math.abs(a - s) < Math.abs(b - s))
        return a;
    else
        return b;
}
  
// To find the sum closest to zero
// Since sum can be negative, we will add MAX
// to it to make it positive
static int MinDiff(int i, int sum,
                   int arr[], int n)
{
  
    // Base cases
    if (i == n)
        return 0;
          
    // Checks if a state is already solved
    if (visit[i][sum + MAX] > 0 )
        return dp[i][sum + MAX];
    visit[i][sum + MAX] = 1;
  
    // Recurrence relation
    dp[i][sum + MAX] = RetClose(arr[i] +
                        MinDiff(i + 1, sum + arr[i], arr, n),
                        MinDiff(i + 1, sum, arr, n), -1 * sum);
  
    // Returning the value
    return dp[i][sum + MAX];
}
  
// Function to calculate the closest sum value
static void FindClose(int arr[], int n)
{
    int ans = inf;
  
    // Calculate the Closest value for every
    // subarray arr[i-1:n]
    for (int i = 1; i <= n; i++)
        ans = RetClose(arr[i - 1] +
            MinDiff(i, arr[i - 1], 
                       arr, n), ans, 0);
  
        System.out.println(ans);
}
  
// Driver Code
public static void main (String[] args) 
{
  
    // Input array
    int arr[] = { 25, -9, -10, -4, -7, -33 };
    int n = arr.length;
      
    FindClose(arr,n);
}
}
  
// This code is contributed by ajit_00023@


Python3
# Python3 Code for above implementation
import numpy as np
  
arrSize = 51 
maxSum = 201 
MAX = 100 
inf = 999999 
  
# Variable to store states of dp 
dp = np.zeros((arrSize,maxSum)); 
visit = np.zeros((arrSize,maxSum)); 
  
# Function to return the number closer to integer s 
def RetClose(a, b, s) : 
  
    if (abs(a - s) < abs(b - s)) :
        return a; 
    else :
        return b; 
  
  
# To find the sum closest to zero 
# Since sum can be negative, we will add MAX 
# to it to make it positive 
def MinDiff(i, sum, arr, n) : 
  
    # Base cases 
    if (i == n) :
        return 0; 
          
    # Checks if a state is already solved 
    if (visit[i][sum + MAX]) :
        return dp[i][sum + MAX];
          
    visit[i][sum + MAX] = 1; 
  
    # Recurrence relation 
    dp[i][sum + MAX] = RetClose(arr[i] + 
                        MinDiff(i + 1, sum + arr[i], arr, n), 
                        MinDiff(i + 1, sum, arr, n), -1 * sum); 
  
    # Returning the value 
    return dp[i][sum + MAX]; 
  
  
# Function to calculate the closest sum value 
def FindClose(arr,n) : 
  
    ans=inf; 
  
    # Calculate the Closest value for every 
    # subarray arr[i-1:n] 
    for i in range(1, n + 1) :
        ans = RetClose(arr[i - 1] + 
                MinDiff(i, arr[i - 1], arr, n), ans, 0); 
  
    print(ans); 
  
  
# Driver function 
if __name__ == "__main__" : 
  
    # Input array 
    arr = [ 25, -9, -10, -4, -7, -33 ]; 
    n = len(arr); 
      
    FindClose(arr,n); 
      
    # This code is contributed by AnkitRai01


C#
// C# Program for above approach
using System;
  
class GFG 
{
      
static int arrSize = 51;
static int maxSum = 201;
static int MAX = 100;
static int inf = 999999;
  
// Variable to store states of dp
static int [,]dp = new int [arrSize,maxSum];
static int [,]visit = new int [arrSize,maxSum];
  
// Function to return the number 
// closer to integer s
static int RetClose(int a, int b, int s)
{
    if (Math.Abs(a - s) < Math.Abs(b - s))
        return a;
    else
        return b;
}
  
// To find the sum closest to zero
// Since sum can be negative, we will add MAX
// to it to make it positive
static int MinDiff(int i, int sum,
                int []arr, int n)
{
  
    // Base cases
    if (i == n)
        return 0;
          
    // Checks if a state is already solved
    if (visit[i,sum + MAX] > 0 )
        return dp[i,sum + MAX];
    visit[i,sum + MAX] = 1;
  
    // Recurrence relation
    dp[i,sum + MAX] = RetClose(arr[i] +
                        MinDiff(i + 1, sum + arr[i], arr, n),
                        MinDiff(i + 1, sum, arr, n), -1 * sum);
  
    // Returning the value
    return dp[i,sum + MAX];
}
  
// Function to calculate the closest sum value
static void FindClose(int []arr, int n)
{
    int ans = inf;
  
    // Calculate the Closest value for every
    // subarray arr[i-1:n]
    for (int i = 1; i <= n; i++)
        ans = RetClose(arr[i - 1] +
            MinDiff(i, arr[i - 1], 
                    arr, n), ans, 0);
  
        Console.WriteLine(ans);
}
  
// Driver Code
public static void Main () 
{
  
    // Input array
    int []arr = { 25, -9, -10, -4, -7, -33 };
    int n = arr.Length;
      
    FindClose(arr,n);
}
}
  
// This code is contributed by  anuj_67..


输出:
-1

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