给定一个数组 arr[]。确定是否可以将数组拆分为两个集合,使得两个集合中元素的总和相等。如果可能,则打印两套。如果不可能,则输出-1。
例子 :
Input : arr = {5, 5, 1, 11}
Output : Set 1 = {5, 5, 1}, Set 2 = {11}
Sum of both the sets is 11 and equal.
Input : arr = {1, 5, 3}
Output : -1
No partitioning results in equal sum sets.
推荐:请先在 IDE 上尝试您的方法,然后再查看解决方案。
先决条件:分区问题
方法:在上一篇文章中,讨论了使用递归的解决方案。在这篇文章中,解释了使用动态规划的解决方案。
这个想法是声明两个集合 set 1 和 set 2。要恢复解决方案,从最终结果 dp[n][k] 开始向后遍历布尔 dp 表,其中 n = 元素数,k = sum/2。集合 1 将包含对总和 k 有贡献的元素,而其他没有贡献的元素将添加到集合 2。在每个位置执行这些步骤以恢复解。
- 检查 dp[i-1][sum] 是否为真。如果为真,则当前元素对总和 k 没有贡献。将此元素添加到集合 2。将索引 i 更新为 i-1,总和保持不变。
- 如果 dp[i-1][sum] 为假,则当前元素对总和 k 有贡献。将当前元素添加到集合 1。通过 i-1 更新索引 i 并通过 sum-arr[i-1] 更新总和。
重复上述步骤,直到遍历每个索引位置。
执行:
C++
// CPP program to print equal sum sets of array.
#include
using namespace std;
// Function to print equal sum
// sets of array.
void printEqualSumSets(int arr[], int n)
{
int i, currSum;
// Finding sum of array elements
int sum = accumulate(arr, arr+n, 0);
// Check sum is even or odd. If odd
// then array cannot be partitioned.
// Print -1 and return.
if (sum & 1) {
cout << "-1";
return;
}
// Divide sum by 2 to find
// sum of two possible subsets.
int k = sum >> 1;
// Boolean DP table to store result
// of states.
// dp[i][j] = true if there is a
// subset of elements in first i elements
// of array that has sum equal to j.
bool dp[n + 1][k + 1];
// If number of elements are zero, then
// no sum can be obtained.
for (i = 1; i <= k; i++)
dp[0][i] = false;
// Sum 0 can be obtained by not selecting
// any element.
for (i = 0; i <= n; i++)
dp[i][0] = true;
// Fill the DP table in bottom up manner.
for (i = 1; i <= n; i++) {
for (currSum = 1; currSum <= k; currSum++) {
// Excluding current element.
dp[i][currSum] = dp[i - 1][currSum];
// Including current element
if (arr[i - 1] <= currSum)
dp[i][currSum] = dp[i][currSum] |
dp[i - 1][currSum - arr[i - 1]];
}
}
// Required sets set1 and set2.
vector set1, set2;
// If partition is not possible print
// -1 and return.
if (!dp[n][k]) {
cout << "-1\n";
return;
}
// Start from last element in dp table.
i = n;
currSum = k;
while (i > 0 && currSum >= 0) {
// If current element does not
// contribute to k, then it belongs
// to set 2.
if (dp[i - 1][currSum]) {
i--;
set2.push_back(arr[i]);
}
// If current element contribute
// to k then it belongs to set 1.
else if (dp[i - 1][currSum - arr[i - 1]]) {
i--;
currSum -= arr[i];
set1.push_back(arr[i]);
}
}
// Print elements of both the sets.
cout << "Set 1 elements: ";
for (i = 0; i < set1.size(); i++)
cout << set1[i] << " ";
cout << "\nSet 2 elements: ";
for (i = 0; i < set2.size(); i++)
cout << set2[i] << " ";
}
// Driver program.
int main()
{
int arr[] = { 5, 5, 1, 11 };
int n = sizeof(arr) / sizeof(arr[0]);
printEqualSumSets(arr, n);
return 0;
}
Java
// Java program to print
// equal sum sets of array.
import java.io.*;
import java.util.*;
class GFG
{
// Function to print equal
// sum sets of array.
static void printEqualSumSets(int []arr,
int n)
{
int i, currSum, sum = 0;
// Finding sum of array elements
for (i = 0; i < arr.length; i++)
sum += arr[i];
// Check sum is even or odd.
// If odd then array cannot
// be partitioned. Print -1
// and return.
if ((sum & 1) == 1)
{
System.out.print("-1");
return;
}
// Divide sum by 2 to find
// sum of two possible subsets.
int k = sum >> 1;
// Boolean DP table to store
// result of states.
// dp[i,j] = true if there is a
// subset of elements in first i
// elements of array that has sum
// equal to j.
boolean [][]dp = new boolean[n + 1][k + 1];
// If number of elements are zero,
// then no sum can be obtained.
for (i = 1; i <= k; i++)
dp[0][i] = false;
// Sum 0 can be obtained by
// not selecting any element.
for (i = 0; i <= n; i++)
dp[i][0] = true;
// Fill the DP table
// in bottom up manner.
for (i = 1; i <= n; i++)
{
for (currSum = 1;
currSum <= k;
currSum++)
{
// Excluding current element.
dp[i][currSum] = dp[i - 1][currSum];
// Including current element
if (arr[i - 1] <= currSum)
dp[i][currSum] = dp[i][currSum] |
dp[i - 1][currSum - arr[i - 1]];
}
}
// Required sets set1 and set2.
List set1 = new ArrayList();
List set2 = new ArrayList();
// If partition is not possible
// print -1 and return.
if (!dp[n][k])
{
System.out.print("-1\n");
return;
}
// Start from last
// element in dp table.
i = n;
currSum = k;
while (i > 0 && currSum >= 0)
{
// If current element does
// not contribute to k, then
// it belongs to set 2.
if (dp[i - 1][currSum])
{
i--;
set2.add(arr[i]);
}
// If current element contribute
// to k then it belongs to set 1.
else if (dp[i - 1][currSum - arr[i - 1]])
{
i--;
currSum -= arr[i];
set1.add(arr[i]);
}
}
// Print elements of both the sets.
System.out.print("Set 1 elements: ");
for (i = 0; i < set1.size(); i++)
System.out.print(set1.get(i) + " ");
System.out.print("\nSet 2 elements: ");
for (i = 0; i < set2.size(); i++)
System.out.print(set2.get(i) + " ");
}
// Driver Code
public static void main(String args[])
{
int []arr = new int[]{ 5, 5, 1, 11 };
int n = arr.length;
printEqualSumSets(arr, n);
}
}
// This code is contributed by
// Manish Shaw(manishshaw1)
Python3
# Python3 program to print equal sum
# sets of array.
import numpy as np
# Function to print equal sum
# sets of array.
def printEqualSumSets(arr, n) :
# Finding sum of array elements
sum_array = sum(arr)
# Check sum is even or odd. If odd
# then array cannot be partitioned.
# Print -1 and return.
if (sum_array & 1) :
print("-1")
return
# Divide sum by 2 to find
# sum of two possible subsets.
k = sum_array >> 1
# Boolean DP table to store result
# of states.
# dp[i][j] = true if there is a
# subset of elements in first i elements
# of array that has sum equal to j.
dp = np.zeros((n + 1, k + 1))
# If number of elements are zero, then
# no sum can be obtained.
for i in range(1, k + 1) :
dp[0][i] = False
# Sum 0 can be obtained by not
# selecting any element.
for i in range(n + 1) :
dp[i][0] = True
# Fill the DP table in bottom up manner.
for i in range(1, n + 1) :
for currSum in range(1, k + 1) :
# Excluding current element.
dp[i][currSum] = dp[i - 1][currSum]
# Including current element
if (arr[i - 1] <= currSum) :
dp[i][currSum] = (dp[i][currSum] or
dp[i - 1][currSum - arr[i - 1]])
# Required sets set1 and set2.
set1, set2 = [], []
# If partition is not possible print
# -1 and return.
if ( not dp[n][k]) :
print("-1")
return
# Start from last element in dp table.
i = n
currSum = k
while (i > 0 and currSum >= 0) :
# If current element does not
# contribute to k, then it belongs
# to set 2.
if (dp[i - 1][currSum]) :
i -= 1
set2.append(arr[i])
# If current element contribute
# to k then it belongs to set 1.
elif (dp[i - 1][currSum - arr[i - 1]]) :
i -= 1
currSum -= arr[i]
set1.append(arr[i])
# Print elements of both the sets.
print("Set 1 elements:", end = " ")
for i in range(len(set1)) :
print(set1[i], end = " ")
print("\nSet 2 elements:", end = " ")
for i in range(len(set2)) :
print(set2[i], end = " ")
# Driver Code
if __name__ == "__main__" :
arr = [ 5, 5, 1, 11 ]
n = len(arr)
printEqualSumSets(arr, n)
# This code is contributed by Ryuga
C#
// C# program to print
// equal sum sets of array.
using System;
using System.Linq;
using System.Collections.Generic;
class GFG
{
// Function to print equal
// sum sets of array.
static void printEqualSumSets(int []arr,
int n)
{
int i, currSum, sum = 0;
// Finding sum of array elements
for (i = 0; i < arr.Length; i++)
sum += arr[i];
// Check sum is even or odd.
// If odd then array cannot
// be partitioned. Print -1
// and return.
if ((sum & 1) == 1)
{
Console.Write("-1");
return;
}
// Divide sum by 2 to find
// sum of two possible subsets.
int k = sum >> 1;
// Boolean DP table to store
// result of states.
// dp[i,j] = true if there is a
// subset of elements in first i
// elements of array that has sum
// equal to j.
bool [,]dp = new bool[n + 1, k + 1];
// If number of elements are zero,
// then no sum can be obtained.
for (i = 1; i <= k; i++)
dp[0, i] = false;
// Sum 0 can be obtained by
// not selecting any element.
for (i = 0; i <= n; i++)
dp[i, 0] = true;
// Fill the DP table
// in bottom up manner.
for (i = 1; i <= n; i++)
{
for (currSum = 1; currSum <= k; currSum++)
{
// Excluding current element.
dp[i, currSum] = dp[i - 1, currSum];
// Including current element
if (arr[i - 1] <= currSum)
dp[i, currSum] = dp[i, currSum] |
dp[i - 1, currSum - arr[i - 1]];
}
}
// Required sets set1 and set2.
List set1 = new List();
List set2 = new List();
// If partition is not possible
// print -1 and return.
if (!dp[n, k])
{
Console.Write("-1\n");
return;
}
// Start from last
// element in dp table.
i = n;
currSum = k;
while (i > 0 && currSum >= 0)
{
// If current element does
// not contribute to k, then
// it belongs to set 2.
if (dp[i - 1, currSum])
{
i--;
set2.Add(arr[i]);
}
// If current element contribute
// to k then it belongs to set 1.
else if (dp[i - 1, currSum - arr[i - 1]])
{
i--;
currSum -= arr[i];
set1.Add(arr[i]);
}
}
// Print elements of both the sets.
Console.Write("Set 1 elements: ");
for (i = 0; i < set1.Count; i++)
Console.Write(set1[i] + " ");
Console.Write("\nSet 2 elements: ");
for (i = 0; i < set2.Count; i++)
Console.Write(set2[i] + " ");
}
// Driver Code.
static void Main()
{
int []arr = { 5, 5, 1, 11 };
int n = arr.Length;
printEqualSumSets(arr, n);
}
}
// This cide is contributed by
// Manish Shaw(manishshaw1)
Javascript
输出 :
Set 1 elements: 1 5 5
Set 2 elements: 11
时间复杂度: O(n*k),其中 k = sum(arr) / 2
辅助空间: O(n*k)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。