📜  总和最接近零的子集

📅  最后修改于: 2021-09-17 06:57:07             🧑  作者: Mango

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

一种简单的方法是递归地生成所有可能的子集,并找到总和最接近零的那个。这种方法的时间复杂度为 O(2^n)。
更好的方法是在Pseudo Polynomial Time Complexity 中使用动态编程
让我们假设我们选择的所有元素的总和直到索引 ‘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..


Javascript


输出:
-1

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

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程