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.
- Split the set of integers into 2 subsets say A and B. A having first n/2 integers and B having rest.
- Find all possible subset sums of integers in set A and store in an array X. Similarly calculate all possible subset sums of integers in set B and store in array Y. Hence, Size of each of the array X and Y will be at most 2n/2.
- Now merge these 2 subproblems. Find combinations from array X and Y such that their sum is less than or equal to S.
- One way to do that is simply iterate over all elements of array Y for each element of array X to check the existence of such a combination. This will take O( (2n/2)2) which is equivalent to O(2n).
- To make it less complex, first sort array Y and then iterate over each element of X and for each element x in X use binary search to find maximum element y in Y such that x + y <= S.
- Binary search here helps in reducing complexity from 2nto 2n/2log(2n/2)which is equivalent to 2n/2n.
- Thus our final running time is O(2n/2n).
C++
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll X[2000005],Y[2000005];
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;
}
}
ll solveSubsetSum(ll a[], int n, ll S)
{
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, Y+size_Y);
ll max = 0;
for ( int i=0; i<size_X; i++)
{
if (X[i] <= S)
{
int p = lower_bound(Y, Y+size_Y, S-X[i]) - Y;
if (p == size_Y || Y[p] != (S-X[i]))
p--;
if ((Y[p]+X[i]) > max)
max = Y[p]+X[i];
}
}
return max;
}
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.*;
import java.lang.*;
import java.io.*;
class GFG{
static long X[] = new long [ 2000005 ];
static long Y[] = new long [ 2000005 ];
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)) == 1 )
s += a[j + c];
x[i] = s;
}
}
static long solveSubsetSum( long a[], int n, long S)
{
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 );
Arrays.sort(Y);
long max = 0 ;
for ( int i = 0 ; i < size_X; i++)
{
if (X[i] <= S)
{
int p = lower_bound(Y, S - X[i]);
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 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;
}
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));
}
}
|
Python3
from typing import List
import bisect
X = [ 0 ] * 2000005
Y = [ 0 ] * 2000005
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
def solveSubsetSum(a: List [ int ], n: int , S: int ) - > int :
global Y
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 )
YY = Y[:size_Y]
YY.sort()
Y = YY
maxx = 0
for i in range (size_X):
if (X[i] < = S):
p = bisect.bisect_left(Y, S - X[i])
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
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)))
|
C#
using System;
public class GFG
{
static long [] X = new long [2000005];
static long [] Y = new long [2000005];
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)) == 1)
s += a[j + c];
x[i] = s;
}
}
static long solveSubsetSum( long [] a, int n, long S)
{
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);
Array.Sort(Y);
long max = 0;
for ( int i = 0; i < size_X; i++)
{
if (X[i] <= S)
{
int p = lower_bound(Y, S - X[i]);
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 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;
}
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));
}
}
|
Javascript
<script>
let X = new Array(2000005);
let Y = new Array(2000005);
for (let i = 0; i < 2000005; i++)
{
X[i] = 0;
Y[i] = 0;
}
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)) == 1)
s += a[j + c];
x[i] = s;
}
}
function solveSubsetSum(a,n,S)
{
calcsubarray(a, X, Math.floor(n / 2), 0);
calcsubarray(a, Y, n - Math.floor(n / 2), Math.floor(n / 2));
let size_X = 1 << Math.floor(n / 2);
let size_Y = 1 << (n - Math.floor(n / 2));
Y.sort( function (a,b){ return a-b;});
let max = 0;
for (let i = 0; i < size_X; i++)
{
if (X[i] <= S)
{
let p = lower_bound(Y, S - X[i]);
if (p == size_Y || 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 = -1, r = a.length;
while (l + 1 < r)
{
let m = (l + r) >>> 1;
if (a[m] >= x)
r = m;
else
l = m;
}
return r;
}
let a=[3, 34, 4, 12, 5, 2 ];
let n = a.length;
let S = 10;
document.write( "Largest value smaller " +
"than or equal to given " +
"sum is " +
solveSubsetSum(a, n, S)+ "<br>" );
</script>
|
Output:
Largest value smaller than or equal to given sum is 10
Reference:
Time Complexity: O(
)
Auxiliary Space: O(
)
If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
09 Sep, 2021
Like Article
Save Article