Meet in the middle (original) (raw)

Last Updated : 25 Jun, 2024

Given a set of n integers where n <= 40. Each of them is at most 1012, determine the maximum sum subset having sum less than or equal S where S <= 1018.

**Example:

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.

A Brute Force approach to solve this problem would be find all possible subset sums of N integers and check if it is less than or equal S and keep track of such a subset with maximum sum. The time complexity using this approach would be O(2n) and n is at most 40. 240 will be quite large and hence we need to find more optimal approach.

**Meet in the middle is a search technique which is used when the input is small but not as small that brute force can be used. Like divide and conquer it splits the problem into two, solves them individually and then merge them. But we can’t apply meet in the middle like divide and conquer because we don’t have the same structure as the original problem.

// C++ program to demonstrate working of Meet in the // Middle algorithm for maximum subset sum problem. #include <bits/stdc++.h> 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<<n); i++) { ll s = 0; for (int j=0; j<n; j++) if (i & (1<<j)) s += a[j+c]; x[i] = s; } }

// Returns the maximum possible sum less or equal to S ll solveSubsetSum(ll a[], int n, ll 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)
sort(Y, Y+size_Y);

// To keep track of the maximum sum of a subset
// such that the maximum sum is less than S
ll 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, Y+size_Y, S-X[i]) - Y;

        // 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;

}

// 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

import java.util.*;

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) { // Check inclusion in subset
                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, 0, size_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], size_Y);

            // 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, int size_Y) {

    // x is the target value or key
    int l = -1, r = size_Y;
    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

Python

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#

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) // Check inclusion in subset
            {
                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, 0, size_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], size_Y);

            // 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, int size_Y)
{
    // x is the target value or key
    int l = -1, r = size_Y;
    while (l + 1 < r)
    {
        int m = (l + r) / 2;
        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;
    Console.WriteLine("Largest value smaller " +
                    "than or equal to given " +
                    "sum is " +
                    solveSubsetSum(a, n, S));
}

}

JavaScript

function calcsubarray(a, x, n, c) { for (let i = 0; i < (1 << n); i++) { let s = 0; for (let j = 0; j < n; j++) { if (i & (1 << j)) { // Check if j-th bit is set in i s += a[j + c]; } } x[i] = s; } }

function solveSubsetSum(a, n, S) { let X = new Array(1 << (n / 2)).fill(0); let Y = new Array(1 << (n - (n / 2))).fill(0);

// Compute all subset sums of first and second halves
calcsubarray(a, X, n / 2, 0);
calcsubarray(a, Y, n - (n / 2), n / 2);

// Sort Y (we need to do binary search in it)
Y.sort((a, b) => a - b);

let max = 0;

// Traverse all elements of X and do
// Binary Search for a pair in Y with
// maximum sum less than S.
for (let i = 0; i < X.length; i++) {
    if (X[i] <= S) {
        let p = lower_bound(Y, S - X[i]);

        if (p > 0 && Y[p] !== (S - X[i]))
            p--;

        if ((Y[p] + X[i]) > max)
            max = Y[p] + X[i];
    }
}
return max;

}

function lower_bound(a, x) { let l = 0, r = a.length; while (l < r) { let m = Math.floor((l + r) / 2); if (a[m] >= x) r = m; else l = m + 1; } return l; }

// Driver code let a = [3, 34, 4, 12, 5, 2]; let n = a.length; let S = 10; console.log("Largest value smaller than or equal to given sum is " + solveSubsetSum(a, n, S));

`

**Output:

Largest value smaller than or equal to given sum is 10

**Reference:

**Time Complexity: O(2 ^{n/2} * log(2 ^{n/2}) )
**Auxiliary Space: O(2 ^ {n/2} )