给定一组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