📜  在中间相遇

📅  最后修改于: 2021-05-04 14:05:21             🧑  作者: Mango

给定一组n整数,其中n <=40。它们中的每个整数最多为10 12 ,确定总和小于或等于S的最大和子子集,其中S <= 10 18

例子:

Input  : set[] = {45, 34, 4, 12, 5, 2} and S = 42
Output : 41
Maximum possible subset sum is 41 which can be 
obtained by summing 34, 5 and 2.

Input  : Set[] = {3, 34, 4, 12, 5, 2} and S = 10
Output : 10
Maximum possible subset sum is 10 which can be 
obtained by summing 2, 3 and 5.

解决该问题的蛮力方法是找到N个整数的所有可能子集和,并检查它是否小于或等于S,并跟踪具有最大和的子集。使用此方法的时间复杂度将为O(2 n ),并且n最多为40。2 40将非常大,因此我们需要找到更理想的方法。

中间的Meet是一种搜索技术,当输入量很小但不能使用蛮力时可以使用该搜索技术。就像分而治之一样,它将问题分成两部分,分别解决,然后合并。但是我们不能像分而治之那样在中间应用见面,因为我们没有与原始问题相同的结构。

  • 将整数集合分为两个子集,例如A和B。A具有前n / 2个整数,B具有休息。
  • 在集合A中找到所有可能的整数子集和并存储在数组X中。类似地,计算集合B中所有可能的整数子集和并存储在数组Y中。因此,数组X和Y的大小最大为2 n / 2
  • 现在合并这两个子问题。从数组X和Y中查找组合,使它们的总和小于或等于S。
    • 一种方法是简单地对数组X的每个元素遍历数组Y的所有元素,以检查这种组合的存在。这将取等于O(2 n )的O((2 n / 2 ) 2 )。
    • 为了使其更简单,首先对数组Y排序,然后遍历X的每个元素,对于X中的每个元素x,使用二进制搜索来找到Y中的最大元素y,以使x + y <=S。
    • 此处的二进制搜索有助于将复杂度从2 n降低到2 n / 2 log(2 n / 2 ),它等效于2 n / 2 n。
    • 因此,我们的最终运行时间为O(2 n / 2 n)。
C++
// C++ program to demonstrate working of Meet in the
// Middle algorithm for maximum subset sum problem.
#include 
using namespace std;
typedef long long int ll;
ll X[2000005],Y[2000005];
 
// Find all possible sum of elements of a[] and store
// in x[]
void calcsubarray(ll a[], ll x[], int n, int c)
{
    for (int i=0; i<(1< max)
                max = Y[p]+X[i];
        }
    }
    return max;
}
 
// Driver code
int main()
{
    ll a[] = {3, 34, 4, 12, 5, 2};
    int n=sizeof(a)/sizeof(a[0]);
    ll S = 10;
    printf("Largest value smaller than or equal to given "
           "sum is %lld\n", solveSubsetSum(a,n,S));
    return 0;
}


Java
// Java program to demonstrate working of
// Meet in the Middle algorithm for
// maximum subset sum problem
import java.util.*;
import java.lang.*;
import java.io.*;
 
class GFG{
     
static long X[] = new long[2000005];
static long Y[] = new long[2000005];
  
// Find all possible sum of elements of a[]
// and store in x[]
static void calcsubarray(long a[],long x[],
                         int n, int c)
{
    for(int i = 0; i < (1 << n); i++)
    {
        long s = 0;
        for(int j = 0; j < n; j++)
            if ((i & (1 << j)) == 0)
                s += a[j + c];
                 
        x[i] = s;
    }
}
 
// Returns the maximum possible sum
// less or equal to S 
static long solveSubsetSum(long a[], int n, long S)
{
     
    // Compute all subset sums of first and second
    // halves
    calcsubarray(a, X, n / 2, 0);
    calcsubarray(a, Y, n - n / 2, n / 2);
     
    int size_X = 1 << (n / 2);
    int size_Y = 1 << (n - n / 2);
     
    // Sort Y (we need to do doing
    // binary search in it)
    Arrays.sort(Y);
     
    // To keep track of the maximum sum
    // of a subset such that the maximum
    // sum is less than S
    long max = 0;
     
    // Traverse all elements of X and do
    // Binary Search for a pair in Y with
    // maximum sum less than S.
    for(int i = 0; i < size_X; i++)
    {
        if (X[i] <= S)
        {
             
            // lower_bound() returns the first address
            // which has value greater than or equal to
            // S-X[i].
            int p = lower_bound(Y, S - X[i]);
     
            // If S-X[i] was not in array Y then
            // decrease p by 1
            if (p == size_Y || Y[p] != (S - X[i]))
                p--;
     
            if ((Y[p] + X[i]) > max)
                max = Y[p] + X[i];
        }
    }
    return max;
}
 
static int lower_bound(long a[], long x)
{
     
    // x is the target value or key
    int l = -1, r = a.length;
    while (l + 1 < r)
    {
        int m = (l + r) >>> 1;
        if (a[m] >= x)
            r = m;
        else
            l = m;
    }
    return r;
}
 
// Driver code
public static void main (String[] args)
{
    long a[] = { 3, 34, 4, 12, 5, 2 };
    int n = a.length;
    long S = 10;
    System.out.println("Largest value smaller " +
                       "than or equal to given " +
                       "sum is " +
                       solveSubsetSum(a, n, S));
}
}
 
// This code is contributed by jyoti369


Python3
# Python program to demonstrate working of Meet in the
# Middle algorithm for maximum subset sum problem.
from typing import List
import bisect
X = [0] * 2000005
Y = [0] * 2000005
 
# Find all possible sum of elements of a[] and store
# in x[]
def calcsubarray(a: List[int], x: List[int], n: int, c: int) -> None:
    for i in range((1 << n)):
        s = 0
        for j in range(n):
            if (i & (1 << j)):
                s += a[j + c]
        x[i] = s
 
# Returns the maximum possible sum less or equal to S
def solveSubsetSum(a: List[int], n: int, S: int) -> int:
    global Y
     
    # Compute all subset sums of first and second
    # halves
    calcsubarray(a, X, n // 2, 0)
    calcsubarray(a, Y, n - n // 2, n // 2)
    size_X = 1 << (n // 2)
    size_Y = 1 << (n - n // 2)
 
    # Sort Y (we need to do doing binary search in it)
    YY = Y[:size_Y]
    YY.sort()
    Y = YY
 
    # To keep track of the maximum sum of a subset
    # such that the maximum sum is less than S
    maxx = 0
 
    # Traverse all elements of X and do Binary Search
    # for a pair in Y with maximum sum less than S.
    for i in range(size_X):
 
        if (X[i] <= S):
 
            # lower_bound() returns the first address
            # which has value greater than or equal to
            # S-X[i].
            p = bisect.bisect_left(Y, S - X[i])
 
            # If S-X[i] was not in array Y then decrease
            # p by 1
            if (p == size_Y or (p < size_Y and Y[p] != (S - X[i]))):
                p -= 1
            if ((Y[p] + X[i]) > maxx):
                maxx = Y[p] + X[i]
    return maxx
 
# Driver code
if __name__ == "__main__":
 
    a = [3, 34, 4, 12, 5, 2]
    n = len(a)
    S = 10
    print("Largest value smaller than or equal to given sum is {}".format(
        solveSubsetSum(a, n, S)))
 
# This code is contributed by sanjeev2552


C#
// C# program to demonstrate working of
// Meet in the Middle algorithm for
// maximum subset sum problem
using System;
public class GFG
{
 
  static long[] X = new long[2000005];
  static long[] Y = new long[2000005];
 
  // Find all possible sum of elements of a[]
  // and store in x[]
  static void calcsubarray(long[] a,long[] x,
                           int n, int c)
  {
    for(int i = 0; i < (1 << n); i++)
    {
      long s = 0;
      for(int j = 0; j < n; j++)
        if ((i & (1 << j)) == 0)
          s += a[j + c];         
      x[i] = s;
    }
  }
 
  // Returns the maximum possible sum
  // less or equal to S 
  static long solveSubsetSum(long[] a, int n, long S)
  {
 
    // Compute all subset sums of first and second
    // halves
    calcsubarray(a, X, n / 2, 0);
    calcsubarray(a, Y, n - n / 2, n / 2);
    int size_X = 1 << (n / 2);
    int size_Y = 1 << (n - n / 2);
 
    // Sort Y (we need to do doing
    // binary search in it)
    Array.Sort(Y);
 
    // To keep track of the maximum sum
    // of a subset such that the maximum
    // sum is less than S
    long max = 0;
 
    // Traverse all elements of X and do
    // Binary Search for a pair in Y with
    // maximum sum less than S.
    for(int i = 0; i < size_X; i++)
    {
      if (X[i] <= S)
      {
 
        // lower_bound() returns the first address
        // which has value greater than or equal to
        // S-X[i].
        int p = lower_bound(Y, S - X[i]);
 
        // If S-X[i] was not in array Y then
        // decrease p by 1
        if (p == size_Y || Y[p] != (S - X[i]))
          p--;
        if ((Y[p] + X[i]) > max)
          max = Y[p] + X[i];
      }
    }
    return max;
  }
 
  static int lower_bound(long[] a, long x)
  {
 
    // x is the target value or key
    int l = -1, r = a.Length;
    while (l + 1 < r)
    {
      int m = (l + r) >> 1;
      if (a[m] >= x)
        r = m;
      else
        l = m;
    }
    return r;
  }
 
  // Driver code
  static public void Main ()
  {
    long[] a = { 3, 34, 4, 12, 5, 2 };
    int n = a.Length;
    long S = 10;
    Console.WriteLine("Largest value smaller " +
                      "than or equal to given " +
                      "sum is " +
                      solveSubsetSum(a, n, S));
  }
}
 
// This code is contributed by Dharanendra L V.


输出:

Largest value smaller than or equal to given sum is 10

参考:

  • https://www.quora.com/What-is-meet-in-the-middle-algorithm-wrt-competitive-programming