📌  相关文章
📜  计算将数组拆分为成对子集的方法,它们之间的总和之差等于K

📅  最后修改于: 2021-04-17 14:04:30             🧑  作者: Mango

给定一个由n个整数和一个整数K组成的数组arr [] ,任务是找到将数组拆分为成对的子集的方式数,以使它们的和之间的差为K。

例子:

天真的方法:解决给定问题的简单方法是生成所有可能的子集,并将每个子集的总和存储在一个数组中,例如, subset [] 。然后,检查数组subset []中是否存在任何对,其对的差为K。检查所有对之后,将这些对的总数打印为结果。
时间复杂度: O(2 N )
辅助空间: O(2 N )

高效方法:可以通过以下观察对上述方法进行优化。

令第一和第二子集的总和分别为S1S2 ,并且数组元素的总和为Y。

因此,对于具有和S1S2的一对子集,等式(3)必须成立,即,子集的元素之和必须等于(K + Y)/ 2 。现在,问题减少到计算具有给定总和的子集的数量。使用动态编程可以解决此问题,其动态关系如下:

在这里, dp [i] [C]存储子数组arr [i…N – 1]的子集数,以使它们的总和等于C。
因此,重复是非常琐碎的,因为只有两个选择,即要么考虑子集中的i数组元素,要么不考虑。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
#define maxN 20
#define maxSum 50
#define minSum 50
#define base 50
 
// To store the states of DP
int dp[maxN][maxSum + minSum];
bool v[maxN][maxSum + minSum];
 
// Function to find count of subsets
// with a given sum
int findCnt(int* arr, int i,
            int required_sum,
            int n)
{
    // Base case
    if (i == n) {
        if (required_sum == 0)
            return 1;
        else
            return 0;
    }
 
    // If an already computed
    // subproblem occurs
    if (v[i][required_sum + base])
        return dp[i][required_sum + base];
 
    // Set the state as solved
    v[i][required_sum + base] = 1;
 
    // Recurrence relation
    dp[i][required_sum + base]
        = findCnt(arr, i + 1,
                  required_sum, n)
          + findCnt(arr, i + 1,
                    required_sum - arr[i], n);
    return dp[i][required_sum + base];
}
 
// Function to count ways to split array into
// pair of subsets with difference K
void countSubsets(int* arr, int K,
                  int n)
{
 
    // Store the total sum of
    // element of the array
    int sum = 0;
 
    // Traverse the array
    for (int i = 0; i < n; i++) {
 
        // Calculate sum of array elements
        sum += arr[i];
    }
 
    // Store the required sum
    int S1 = (sum + K) / 2;
 
    // Print the number of subsets
    // with sum equal to S1
    cout << findCnt(arr, 0, S1, n);
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 1, 2, 3 };
    int N = sizeof(arr) / sizeof(int);
    int K = 1;
 
    // Function Call
    countSubsets(arr, K, N);
 
    return 0;
}


Java
// Java program for the above approach
import java.io.*;
import java.util.*;
 
class GFG
{
  static int maxN = 20;
  static int maxSum = 50;
  static int minSum = 50;
  static int Base = 50;
 
  // To store the states of DP
  static int[][] dp = new int[maxN][maxSum + minSum];
  static boolean[][] v = new boolean[maxN][maxSum + minSum];
 
  // Function to find count of subsets
  // with a given sum
  static int findCnt(int[] arr, int i,
                     int required_sum,
                     int n)
  {
    // Base case
    if (i == n) {
      if (required_sum == 0)
        return 1;
      else
        return 0;
    }
 
    // If an already computed
    // subproblem occurs
    if (v[i][required_sum + Base])
      return dp[i][required_sum + Base];
 
    // Set the state as solved
    v[i][required_sum + Base] = true;
 
    // Recurrence relation
    dp[i][required_sum + Base]
      = findCnt(arr, i + 1,
                required_sum, n)
      + findCnt(arr, i + 1,
                required_sum - arr[i], n);
    return dp[i][required_sum + Base];
  }  
 
  // Function to count ways to split array into
  // pair of subsets with difference K
  static void countSubsets(int[] arr, int K,
                           int n)
  {
    // Store the total sum of
    // element of the array
    int sum = 0;
 
    // Traverse the array
    for (int i = 0; i < n; i++)
    {
 
      // Calculate sum of array elements
      sum += arr[i];
    }
 
    // Store the required sum
    int S1 = (sum + K) / 2;
 
    // Print the number of subsets
    // with sum equal to S1
    System.out.print(findCnt(arr, 0, S1, n));
  } 
 
 
  // Driver Code
  public static void main(String[] args)
  {
    int[] arr = { 1, 1, 2, 3 };
    int N = arr.length;
    int K = 1;
 
    // Function Call
    countSubsets(arr, K, N);
  }
}
 
// This code is contributed by sanjoy_62.


Python3
# Python program for the above approach
maxN = 20;
maxSum = 50;
minSum = 50;
Base = 50;
 
# To store the states of DP
dp = [[0 for i in range(maxSum + minSum)] for j in range(maxN)];
v = [[False for i in range(maxSum + minSum)] for j in range(maxN)];
 
# Function to find count of subsets
# with a given sum
def findCnt(arr, i, required_sum, n):
   
    # Base case
    if (i == n):
        if (required_sum == 0):
            return 1;
        else:
            return 0;
 
    # If an already computed
    # subproblem occurs
    if (v[i][required_sum + Base]):
        return dp[i][required_sum + Base];
 
    # Set the state as solved
    v[i][required_sum + Base] = True;
 
    # Recurrence relation
    dp[i][required_sum + Base] = findCnt(arr, i + 1, required_sum, n)\
    + findCnt(arr, i + 1, required_sum - arr[i], n);
    return dp[i][required_sum + Base];
 
# Function to count ways to split array into
# pair of subsets with difference K
def countSubsets(arr, K, n):
   
    # Store the total sum of
    # element of the array
    sum = 0;
 
    # Traverse the array
    for i in range(n):
       
        # Calculate sum of array elements
        sum += arr[i];
 
    # Store the required sum
    S1 = (sum + K) // 2;
 
    # Prthe number of subsets
    # with sum equal to S1
    print(findCnt(arr, 0, S1, n));
 
# Driver Code
if __name__ == '__main__':
    arr = [1, 1, 2, 3];
    N = len(arr);
    K = 1;
 
    # Function Call
    countSubsets(arr, K, N);
 
    # This code is contributed by shikhasingrajput


C#
// C# program for the above approach
using System;
class GFG {
     
    static int maxN = 20;
    static int maxSum = 50;
    static int minSum = 50;
    static int Base = 50;
     
    // To store the states of DP
    static int[,] dp = new int[maxN, maxSum + minSum];
    static bool[,] v = new bool[maxN, maxSum + minSum];
       
    // Function to find count of subsets
    // with a given sum
    static int findCnt(int[] arr, int i,
                int required_sum,
                int n)
    {
        // Base case
        if (i == n) {
            if (required_sum == 0)
                return 1;
            else
                return 0;
        }
       
        // If an already computed
        // subproblem occurs
        if (v[i, required_sum + Base])
            return dp[i, required_sum + Base];
       
        // Set the state as solved
        v[i,required_sum + Base] = true;
       
        // Recurrence relation
        dp[i,required_sum + Base]
            = findCnt(arr, i + 1,
                      required_sum, n)
              + findCnt(arr, i + 1,
                        required_sum - arr[i], n);
        return dp[i,required_sum + Base];
    }
       
    // Function to count ways to split array into
    // pair of subsets with difference K
    static void countSubsets(int[] arr, int K,
                      int n)
    {
       
        // Store the total sum of
        // element of the array
        int sum = 0;
       
        // Traverse the array
        for (int i = 0; i < n; i++)
        {
       
            // Calculate sum of array elements
            sum += arr[i];
        }
       
        // Store the required sum
        int S1 = (sum + K) / 2;
       
        // Print the number of subsets
        // with sum equal to S1
        Console.Write(findCnt(arr, 0, S1, n));
    }  
 
  // Driver code
  static void Main()
  {
    int[] arr = { 1, 1, 2, 3 };
    int N = arr.Length;
    int K = 1;
   
    // Function Call
    countSubsets(arr, K, N);
  }
}
 
// This code is contributed by divyeshrabadiya07.


输出:
3

时间复杂度: O(N * K)
辅助空间: O(N * K)