📌  相关文章
📜  查找通过将数组的任何子集划分为相等的2个分区而形成的最大子集和

📅  最后修改于: 2021-04-29 07:11:45             🧑  作者: 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


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


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


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


输出:
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

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

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
输出:
6

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