📜  查找通过将数组的任何子集划分为具有相等总和的 2 个分区而形成的最大子集总和

📅  最后修改于: 2021-09-22 10:01:10             🧑  作者: Mango

给定一个包含 N 个元素的数组 A。将此数组的任何子集划分为两个不相交的子集,使两个子集具有相同的总和。求分区后能得到的最大和。

注意:没有必要对整个数组进行分区,即任何元素都可能不会对任何分区做出贡献。

例子:

天真的方法:
上述问题可以通过使用递归的蛮力方法解决。所有元素都有三种可能性。它要么会影响分区 1 或分区 2,要么不会包含在任何分区中。我们将对每个元素执行这三个操作,并在每个递归步骤中处理下一个元素。

下面是上述方法的实现:

C++
// CPP implementation for the
// above mentioned recursive approach
 
#include 
 
using namespace std;
 
// Function to find the maximum subset sum
int maxSum(int p0, int p1, int a[], int pos, int n)
{
    if (pos == n) {
        if (p0 == p1)
            return p0;
        else
            return 0;
    }
    // Ignore the current element
    int ans = maxSum(p0, p1, a, pos + 1, n);
 
    // including element in partition 1
    ans = max(ans, maxSum(p0 + a[pos], p1, a, pos + 1, n));
 
    // including element in partition 2
    ans = max(ans, maxSum(p0, p1 + a[pos], a, pos + 1, n));
    return ans;
}
 
// Driver code
int main()
{
    // size of the array
    int n = 4;
    int a[n] = { 1, 2, 3, 6 };
    cout << maxSum(0, 0, a, 0, n);
    return 0;
}


Java
// Java implementation for the
// above mentioned recursive approach
class GFG {
     
    // Function to find the maximum subset sum
    static int maxSum(int p0, int p1, int a[], int pos, int n)
    {
        if (pos == n) {
            if (p0 == p1)
                return p0;
            else
                return 0;
        }
 
        // Ignore the current element
        int ans = maxSum(p0, p1, a, pos + 1, n);
     
        // including element in partition 1
        ans = Math.max(ans, maxSum(p0 + a[pos], p1, a, pos + 1, n));
     
        // including element in partition 2
        ans = Math.max(ans, maxSum(p0, p1 + a[pos], a, pos + 1, n));
        return ans;
    }
     
    // Driver code
    public static void main (String[] args)
    {
        // size of the array
        int n = 4;
        int a[] = { 1, 2, 3, 6 };
        System.out.println(maxSum(0, 0, a, 0, n));
         
    }
}
 
// This code is contributed by AnkitRai01


Python3
# Python3 implementation for the
# above mentioned recursive approach
 
# Function to find the maximum subset sum
def maxSum(p0, p1, a, pos, n) :
 
    if (pos == n) :
        if (p0 == p1) :
            return p0;
        else :
            return 0;
     
    # Ignore the current element
    ans = maxSum(p0, p1, a, pos + 1, n);
 
    # including element in partition 1
    ans = max(ans, maxSum(p0 + a[pos], p1, a, pos + 1, n));
 
    # including element in partition 2
    ans = max(ans, maxSum(p0, p1 + a[pos], a, pos + 1, n));
     
    return ans;
 
# Driver code
if __name__ == "__main__" :
 
    # size of the array
    n = 4;
    a = [ 1, 2, 3, 6 ];
     
    print(maxSum(0, 0, a, 0, n));
 
# This code is contributed by AnkitRai01


C#
// C# implementation for the
// above mentioned recursive approach
 
using System;
 
public class GFG {
     
    // Function to find the maximum subset sum
    static int maxSum(int p0, int p1, int []a, int pos, int n)
    {
        if (pos == n) {
            if (p0 == p1)
                return p0;
            else
                return 0;
        }
 
        // Ignore the current element
        int ans = maxSum(p0, p1, a, pos + 1, n);
     
        // including element in partition 1
        ans = Math.Max(ans, maxSum(p0 + a[pos], p1, a, pos + 1, n));
     
        // including element in partition 2
        ans = Math.Max(ans, maxSum(p0, p1 + a[pos], a, pos + 1, n));
        return ans;
    }
     
    // Driver code
    public static void Main (string[] args)
    {
        // size of the array
        int n = 4;
        int []a = { 1, 2, 3, 6 };
        Console.WriteLine(maxSum(0, 0, a, 0, n));
         
    }
}
 
// This code is contributed by AnkitRai01


Javascript


C++
// CPP implementation for the above mentioned
// Dynamic Programming  approach
 
#include 
 
using namespace std;
 
// Function to find the maximum subset sum
int maxSum(int a[], int n)
{
    // sum of all elements
    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += a[i];
 
    int limit = 2 * sum + 1;
 
    // bottom up lookup table;
    int dp[n + 1][limit];
 
    // initialising dp table with INT_MIN
    // where, INT_MIN means no solution
    for (int i = 0; i < n + 1; i++) {
        for (int j = 0; j < limit; j++)
            dp[i][j] = INT_MIN;
    }
 
    // Case when diff is 0
    dp[0][sum] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < limit; j++) {
 
            // Putting ith element in g0
            if ((j - a[i - 1]) >= 0 && dp[i - 1][j - a[i - 1]] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                             + a[i - 1]);
 
            // Putting ith element in g1
            if ((j + a[i - 1]) < limit && dp[i - 1][j + a[i - 1]] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i - 1]]);
 
            // Ignoring ith element
            if (dp[i - 1][j] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j]);
        }
    }
 
    return dp[n][sum];
}
 
// Driver code
 
int main()
{
    int n = 4;
    int a[n] = { 1, 2, 3, 6 };
    cout << maxSum(a, n);
    return 0;
}


Java
// Java implementation for the above mentioned
// Dynamic Programming approach
class GFG {
     
    final static int INT_MIN = Integer.MIN_VALUE;
     
    // Function to find the maximum subset sum
    static int maxSum(int a[], int n)
    {
        // sum of all elements
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
     
        int limit = 2 * sum + 1;
     
        // bottom up lookup table;
        int dp[][] = new int[n + 1][limit];
     
        // initialising dp table with INT_MIN
        // where, INT_MIN means no solution
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < limit; j++)
                dp[i][j] = INT_MIN;
        }
     
        // Case when diff is 0
        dp[0][sum] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < limit; j++) {
     
                // Putting ith element in g0
                if ((j - a[i - 1]) >= 0 && dp[i - 1][j - a[i - 1]] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                                + a[i - 1]);
     
                // Putting ith element in g1
                if ((j + a[i - 1]) < limit && dp[i - 1][j + a[i - 1]] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j + a[i - 1]]);
     
                // Ignoring ith element
                if (dp[i - 1][j] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
            }
        }
     
        return dp[n][sum];
    }
     
    // Driver code
    public static void main (String[] args)
    {
        int n = 4;
        int []a = { 1, 2, 3, 6 };
        System.out.println(maxSum(a, n));
    }
}
 
// This code is contributed by AnkitRai01


Python3
# Python3 implementation for the above mentioned
# Dynamic Programming approach
import numpy as np
import sys
 
INT_MIN = -(sys.maxsize - 1)
 
# Function to find the maximum subset sum
def maxSum(a, n) :
 
    # sum of all elements
    sum = 0;
    for i in range(n) :
        sum += a[i];
 
    limit = 2 * sum + 1;
 
    # bottom up lookup table;
    dp = np.zeros((n + 1,limit));
 
    # initialising dp table with INT_MIN
    # where, INT_MIN means no solution
    for i in range(n + 1) :
        for j in range(limit) :
            dp[i][j] = INT_MIN;
 
    # Case when diff is 0
    dp[0][sum] = 0;
    for i in range(1, n + 1) :
        for j in range(limit) :
 
            # Putting ith element in g0
            if ((j - a[i - 1]) >= 0 and dp[i - 1][j - a[i - 1]] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                            + a[i - 1]);
 
            # Putting ith element in g1
            if ((j + a[i - 1]) < limit and dp[i - 1][j + a[i - 1]] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i - 1]]);
 
            # Ignoring ith element
            if (dp[i - 1][j] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j]);
                 
    return dp[n][sum];
 
# Driver code
 
if __name__ == "__main__" :
 
    n = 4;
    a = [ 1, 2, 3, 6 ];
    print(maxSum(a, n));
 
# This code is contributed by Yash_R


C#
// C# implementation for the above mentioned
// Dynamic Programming approach
using System;
 
class GFG {
     
    static int INT_MIN = int.MinValue;
     
    // Function to find the maximum subset sum
    static int maxSum(int []a, int n)
    {
        // sum of all elements
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
     
        int limit = 2 * sum + 1;
     
        // bottom up lookup table;
        int [,]dp = new int[n + 1,limit];
     
        // initialising dp table with INT_MIN
        // where, INT_MIN means no solution
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < limit; j++)
                dp[i,j] = INT_MIN;
        }
     
        // Case when diff is 0
        dp[0,sum] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < limit; j++) {
     
                // Putting ith element in g0
                if ((j - a[i - 1]) >= 0 && dp[i - 1,j - a[i - 1]] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j - a[i - 1]]
                                                + a[i - 1]);
     
                // Putting ith element in g1
                if ((j + a[i - 1]) < limit && dp[i - 1,j + a[i - 1]] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j + a[i - 1]]);
     
                // Ignoring ith element
                if (dp[i - 1,j] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j]);
            }
        }
     
        return dp[n,sum];
    }
     
    // Driver code
    public static void Main()
    {
        int n = 4;
        int []a = { 1, 2, 3, 6 };
        Console.WriteLine(maxSum(a, n));
    }
}
 
// This code is contributed by Yash_R


Javascript


输出:
6

时间复杂度: O(3^n)

有效的方法:
上述方法可以使用动态规划方法进行优化。
我们将定义我们的 DP 状态如下:

现在我们可能会遇到,和之间的差是负数,在[-sum, +sum]范围内,这里的是所有元素的总和。当一个子集为空而另一个子集包含所有元素时出现的最小和最大范围。因此,在 DP 状态下,我们将 j 定义为 (sum – diff)。因此,j 的范围是 [0, 2*sum]。

下面是上述方法的实现:

C++

// CPP implementation for the above mentioned
// Dynamic Programming  approach
 
#include 
 
using namespace std;
 
// Function to find the maximum subset sum
int maxSum(int a[], int n)
{
    // sum of all elements
    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += a[i];
 
    int limit = 2 * sum + 1;
 
    // bottom up lookup table;
    int dp[n + 1][limit];
 
    // initialising dp table with INT_MIN
    // where, INT_MIN means no solution
    for (int i = 0; i < n + 1; i++) {
        for (int j = 0; j < limit; j++)
            dp[i][j] = INT_MIN;
    }
 
    // Case when diff is 0
    dp[0][sum] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < limit; j++) {
 
            // Putting ith element in g0
            if ((j - a[i - 1]) >= 0 && dp[i - 1][j - a[i - 1]] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                             + a[i - 1]);
 
            // Putting ith element in g1
            if ((j + a[i - 1]) < limit && dp[i - 1][j + a[i - 1]] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i - 1]]);
 
            // Ignoring ith element
            if (dp[i - 1][j] != INT_MIN)
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j]);
        }
    }
 
    return dp[n][sum];
}
 
// Driver code
 
int main()
{
    int n = 4;
    int a[n] = { 1, 2, 3, 6 };
    cout << maxSum(a, n);
    return 0;
}

Java

// Java implementation for the above mentioned
// Dynamic Programming approach
class GFG {
     
    final static int INT_MIN = Integer.MIN_VALUE;
     
    // Function to find the maximum subset sum
    static int maxSum(int a[], int n)
    {
        // sum of all elements
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
     
        int limit = 2 * sum + 1;
     
        // bottom up lookup table;
        int dp[][] = new int[n + 1][limit];
     
        // initialising dp table with INT_MIN
        // where, INT_MIN means no solution
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < limit; j++)
                dp[i][j] = INT_MIN;
        }
     
        // Case when diff is 0
        dp[0][sum] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < limit; j++) {
     
                // Putting ith element in g0
                if ((j - a[i - 1]) >= 0 && dp[i - 1][j - a[i - 1]] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                                + a[i - 1]);
     
                // Putting ith element in g1
                if ((j + a[i - 1]) < limit && dp[i - 1][j + a[i - 1]] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j + a[i - 1]]);
     
                // Ignoring ith element
                if (dp[i - 1][j] != INT_MIN)
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
            }
        }
     
        return dp[n][sum];
    }
     
    // Driver code
    public static void main (String[] args)
    {
        int n = 4;
        int []a = { 1, 2, 3, 6 };
        System.out.println(maxSum(a, n));
    }
}
 
// This code is contributed by AnkitRai01

蟒蛇3

# Python3 implementation for the above mentioned
# Dynamic Programming approach
import numpy as np
import sys
 
INT_MIN = -(sys.maxsize - 1)
 
# Function to find the maximum subset sum
def maxSum(a, n) :
 
    # sum of all elements
    sum = 0;
    for i in range(n) :
        sum += a[i];
 
    limit = 2 * sum + 1;
 
    # bottom up lookup table;
    dp = np.zeros((n + 1,limit));
 
    # initialising dp table with INT_MIN
    # where, INT_MIN means no solution
    for i in range(n + 1) :
        for j in range(limit) :
            dp[i][j] = INT_MIN;
 
    # Case when diff is 0
    dp[0][sum] = 0;
    for i in range(1, n + 1) :
        for j in range(limit) :
 
            # Putting ith element in g0
            if ((j - a[i - 1]) >= 0 and dp[i - 1][j - a[i - 1]] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i - 1]]
                                            + a[i - 1]);
 
            # Putting ith element in g1
            if ((j + a[i - 1]) < limit and dp[i - 1][j + a[i - 1]] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i - 1]]);
 
            # Ignoring ith element
            if (dp[i - 1][j] != INT_MIN) :
 
                dp[i][j] = max(dp[i][j], dp[i - 1][j]);
                 
    return dp[n][sum];
 
# Driver code
 
if __name__ == "__main__" :
 
    n = 4;
    a = [ 1, 2, 3, 6 ];
    print(maxSum(a, n));
 
# This code is contributed by Yash_R

C#

// C# implementation for the above mentioned
// Dynamic Programming approach
using System;
 
class GFG {
     
    static int INT_MIN = int.MinValue;
     
    // Function to find the maximum subset sum
    static int maxSum(int []a, int n)
    {
        // sum of all elements
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
     
        int limit = 2 * sum + 1;
     
        // bottom up lookup table;
        int [,]dp = new int[n + 1,limit];
     
        // initialising dp table with INT_MIN
        // where, INT_MIN means no solution
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < limit; j++)
                dp[i,j] = INT_MIN;
        }
     
        // Case when diff is 0
        dp[0,sum] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < limit; j++) {
     
                // Putting ith element in g0
                if ((j - a[i - 1]) >= 0 && dp[i - 1,j - a[i - 1]] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j - a[i - 1]]
                                                + a[i - 1]);
     
                // Putting ith element in g1
                if ((j + a[i - 1]) < limit && dp[i - 1,j + a[i - 1]] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j + a[i - 1]]);
     
                // Ignoring ith element
                if (dp[i - 1,j] != INT_MIN)
     
                    dp[i,j] = Math.Max(dp[i,j], dp[i - 1,j]);
            }
        }
     
        return dp[n,sum];
    }
     
    // Driver code
    public static void Main()
    {
        int n = 4;
        int []a = { 1, 2, 3, 6 };
        Console.WriteLine(maxSum(a, n));
    }
}
 
// This code is contributed by Yash_R

Javascript


输出:
6

时间复杂度: O(N*Sum)    ,其中 Sum 表示所有数组元素的总和。
辅助空间: O(N*Sum)