[英]Given an array of integers find all “maximal” subsets
Given an upper bound d
and an array of integers, return all subsets (as arrays) whose sum of elements is <= d
and to whom we can't add any other element from the array such that <= d
is not violated. 给定一个上限d
和一个整数数组,返回元素总和为<= d
所有子集(作为数组),并且我们不能向其添加任何其他元素,从而不会违反<= d
。
Example: 例:
d = 4;
int[] arr = {1, 2, 3, 4, 5};
int[][] solution = findAllMaximalSubsets(arr, d);
System.out.println(Arrays.deepToString(solution));
Output: { {1, 2}, {1, 3}, {4} }
This method findAllMaximalSubsets(int[] arr, d)
is a subroutine in another algorithm I'm working on. 这个方法findAllMaximalSubsets(int[] arr, d)
是我正在研究的另一种算法的子例程。 I suspect that the solution will be Np-ish which is fine. 我怀疑解决方案将是Np-ish ,这很好。
Currently I have no approach to tackle this problem :/ 目前我没有办法解决这个问题:/
Not disagreeing with the comments that say Stack Overflow is not the place where code is written for you. 不反对“堆栈溢出不是为您编写代码的地方”的评论。 I think I can explain the details better and more precisely in code than in words, so I do provide code here. 我认为我可以用代码比用文字更好,更准确地解释细节,因此我在这里提供了代码。 Also I admit it was a pleasure writing it (which in itself is no excuse for also posting it). 我也承认编写它是一种乐趣(它本身也不是发布它的借口)。
I am not using any dynamic programming nor any graph here. 我在这里没有使用任何动态编程或任何图形。 I am using the idea of Dawood Ibn Kareem of trying with and without x
and using recursion for the remainder of the problem. 我使用的达乌德·伊本·卡里姆的有和没有尝试的想法x
和使用递归的问题的其余部分。
In each call to the recursive method I am passing the array, a
, and the upper bound, capacity
; 在对递归方法的每次调用中,我都要传递数组a
和上限( capacity
; these are the same in every call. 这些在每个通话中都是相同的。 I pass a partial solution telling which of the previously considered elements are included in the subset currently being built, and the sum of the included elements just for convenience. 我通过了一个部分解决方案,它告诉您当前正在构建的子集中包含了哪些先前考虑的元素,以及所包含元素的总和只是为了方便。 Finally I pass the smallest element left out so far. 最后,我传递到目前为止遗漏的最小元素。 This will allow me to check in the end whether we end up with a set where we cannot add another element. 这将使我最终检查是否以无法添加其他元素的集合结束。
I am not giving you the return type you expected, but I trust you to convert yourself if it's important. 我没有给您期望的返回类型,但是我相信您可以进行重要的转换。 The reason is I assumed array elements are distinct even if some are equal. 原因是我假设即使元素相等,数组元素也是不同的。 If the array is { 1, 3, 2, 3, 5 }
and the solution includes { 1, 3 }
, you don't know which of the 3s I took. 如果数组为{ 1, 3, 2, 3, 5 }
并且解决方案包括{ 1, 3 }
,则您不知道我选了哪3个。 So instead I give you a boolean array of either { true, true, false, false, false }
(if I took the first 3) or { true, false, false, true, false }
(if I took the second 3) (in practice I will give you both). 因此,我改为给您一个{ true, true, false, false, false }
(如果我取前三个)或{ true, false, false, true, false }
(如果我取第二个3)的布尔数组(实际上,我会给你们两个)。
/**
* Calculates all subsets of a that have a sum <= capacity
* and to which one cannot add another element from a without exceeding the capacity.
* @param a elements to put in sets;
* even when two elements from a are equal, they are considered distinct
* @param capacity maximum sum of a returned subset
* @return collection of subsets of a.
* Each subset is represented by a boolean array the same length as a
* where true means that the element in the same index in a is included,
* false that it is not included.
*/
private static Collection<boolean[]> maximalSubsetsWithinCapacity(int[] a, int capacity) {
List<boolean[]> b = new ArrayList<>();
addSubsets(a, capacity, new boolean[0], 0, Integer.MAX_VALUE, b);
return b;
}
/** add to b all allowed subsets where the the membership for the first members of a is determined by paritalSubset
* and where remaining capacity is smaller than smallestMemberLeftOut
*/
private static void addSubsets(int[] a, int capacity, boolean[] partialSubset, int sum,
int smallestMemberLeftOut, List<boolean[]> b) {
assert sum == IntStream.range(0, partialSubset.length)
.filter(ix -> partialSubset[ix])
.map(ix -> a[ix])
.sum()
: Arrays.toString(a) + ' ' + Arrays.toString(partialSubset) + ' ' + sum;
int remainingCapacity = capacity - sum;
if (partialSubset.length == a.length) { // done
// check capacity constraint: if there’s still room for a member of size smallestMemberLeftOut,
// we have violated the maximality constraint
if (remainingCapacity < smallestMemberLeftOut) { // OK, no more members could have been added
b.add(partialSubset);
}
} else {
// try next element from a.
int nextElement = a[partialSubset.length];
// i.e., decide whether should be included.
// try with and without.
// is including nextElement a possibility?
if (nextElement <= remainingCapacity) { // yes
boolean[] newPartialSubset = Arrays.copyOf(partialSubset, partialSubset.length + 1);
newPartialSubset[partialSubset.length] = true; // include member
addSubsets(a, capacity, newPartialSubset, sum + nextElement, smallestMemberLeftOut, b);
}
// try leaving nextElement out
boolean[] newPartialSubset = Arrays.copyOf(partialSubset, partialSubset.length + 1);
newPartialSubset[partialSubset.length] = false; // exclude member
int newSmallestMemberLeftOut = smallestMemberLeftOut;
if (nextElement < smallestMemberLeftOut) {
newSmallestMemberLeftOut = nextElement;
}
addSubsets(a, capacity, newPartialSubset, sum, newSmallestMemberLeftOut, b);
}
It's slightly tricky in a few spots. 在某些地方有些棘手。 I hope my comments will help you through it. 希望我的评论对您有所帮助。 Otherwise please ask. 否则请询问。
Let's try it out: 让我们尝试一下:
int[] a = { 5, 1, 2, 6 };
Collection<boolean[]> b = maximalSubsetsWithinCapacity(a, 8);
b.forEach(ba -> System.out.println(Arrays.toString(ba)));
This code prints: 此代码打印:
[true, true, true, false]
[false, true, false, true]
[false, false, true, true]
[true, true, true, false]
means a subset of 5, 1 and 2. The sum is 8, so this fits the capacity of 8 exactly ( d
). [true, true, true, false]
表示5、1和2的子集。总和为8,因此恰好适合8的容量( d
)。 [false, true, false, true]
means 1 and 6, sum is 7 and we could not add 2 or we would exceed the capacity [false, true, false, true]
表示1和6,总和为7,我们不能相加2,否则将超出容量 [false, false, true, true]
means 2 and 6 and also fits the capacity d
exactly. 最后[false, false, true, true]
表示2和6,并且也恰好适合容量d
。 I believe this exhausts the possibilities within your constraints. 我相信这会尽您所能。
May be you can find all the combination of subset like below and add all subset elements and compare with d. 可能是您可以找到下面所有子集的组合,并添加所有子集元素并与d比较。
=================== ===================
private static void findAllMaximalSubsets(int[] arr,int d) {
for(int i=0;i<arr.length;i++) {
for (int j =i;j< arr.length;j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum = sum + arr[k];
}
if (sum <= d)
//add the array elements from k o j to the 2D arry
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.