Meet in the middle
本文最后更新于:2024年2月12日 晚上
Meet in the middle(折半搜索)
讲解:
https://www.geeksforgeeks.org/meet-in-the-middle/
题目:
描述:
「Meet in the middle」是一个搜索技巧,可以在输入很小但是却不足以小到可以使用暴力法算时使用。就像分治法把问题分成两部分,分别解决,然后合并。但是我们并不能像「分治」那样使用「Meet in the middle」,因为「Meet in the middle」没有和原问题一样的子结构。
将整数集合划分为A、B两个集合。A、B各含有集合中一半的数;
求出集合A中整数所有可能的子集和记录在数组X中。同样求出B中所有可能的子集和并将其存储在数组Y中。因此,数组X和Y的大小最大为$2^{\frac{n}{2}}$;
现在合并两个子问题。找到X和Y的组合中和小于或者等于S的组合。
一种方法是迭代数组Y的所有元素以检查数组X的每个元素是否存在这样的组合。
时间复杂度为:$O((2^{\frac{n}{2}})^{2})=O(2^{n})$
为了简化它,首先将Y进行排序,然后迭代X的每个元素,对X中的每个元素$x$使用二分查找,以找到Y中的最大元素$y$,使$x+y<=S$。
二分查找可以将时间复杂度从$O(2^{n})$降低到$O(2^{\frac{n}{2}}log(2^{\frac{n}{2}}))=O(n2^{\frac{n}{2}})$。
因此最终时间复杂度为:$O(n2^{\frac{n}{2}})$
例子
给定一个大小为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.
import java.util.*;
/**
* @Author: merickbao
* @Created_Time: 2021-10-11 15:52
* @Description: Meet in the middle
*/
public class MeetInTheMiddle {
public static void main(String[] args) {
int[] arr = {3, 34, 4, 12, 5, 2};
int n = arr.length;
int[] A = {3, 34, 4};
int[] B = {12, 5, 2};
int target_sum = 10;
HashMap<Integer, HashSet<Integer>> X = new HashMap<>(), Y = new HashMap<>();
// 计算A B的所有子集可能和
for (int i = 0; i < 1 << (n / 2); i++) {
int sum_A = 0, sum_B = 0;
for (int j = 0; j < n / 2; j++) {
if (((i >> j) & 1) == 1) {
sum_A += A[j];
sum_B += B[j];
}
}
HashSet<Integer> ta = X.getOrDefault(sum_A, new HashSet<>());
HashSet<Integer> tb = Y.getOrDefault(sum_B, new HashSet<>());
ta.add(i);
tb.add(i);
X.put(sum_A, ta);
Y.put(sum_B, tb);
}
// 进行组合
// 1. 暴力组合
int max_sum = -1;
List<Integer> ans = new ArrayList<>();
for (Map.Entry<Integer, HashSet<Integer>> en_A : X.entrySet()) {
int sa = en_A.getKey();
HashSet<Integer> ia = en_A.getValue();
for (Map.Entry<Integer, HashSet<Integer>> en_B : Y.entrySet()) {
int sb = en_B.getKey();
HashSet<Integer> ib = en_B.getValue();
if (sa + sb <= target_sum && sa + sb > max_sum) {
max_sum = sa + sb;
ans.clear();
for (int i : ia) {
ans.add(i);
}
for (int i : ib) {
ans.add(i);
}
}
}
}
System.out.println("Output : " + max_sum);
System.out.print("By : ");
for (int i : ans) {
System.out.print(i + " ");
}
}
}
本文作者: MerickBao
本文链接: https://merickbao.top/post/%E7%AE%97%E6%B3%95/%E8%BF%9B%E9%98%B6%E7%AE%97%E6%B3%95/Meet_in_the_middle.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!