简体   繁体   English

给定整数数组,找到所有“最大”子集

[英]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,否则将超出容量
  • finally [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.

相关问题 给定一个整数数组和一个总和,任务是找出给定数组的子集是否存在总和等于给定总和的子集 - Given an array of integers and a sum, the task is to find if there exists a subsets of given array with sum equal to given sum 给定一个数组,找到总和为值k的所有子集 - Given an array, find all subsets which sum to value k 给定一个整数数组,反转每个最大的严格升序子数组 - Given an array of integers, reverse every maximal strictly ascending subarray 给定一组n个整数,返回总和为0的k个元素的所有子集 - given a set of n integers, return all subsets of k elements that sum to 0 给定一个整数数组(长度为 n),使用 Java 中的递归查找并返回输入数组的所有子集 - Given an integer array (of length n), find and return all the subsets of input array using recursion in Java 在给定整数数组的情况下查找所有增长最长的子序列 - 动态编程 - To find all longest increasing subsequences given an array of integers - Dynamic Programming 使用数组中的前&#39;n&#39;个整数递归打印所有子集 - Recursively Print All Subsets Using First 'n' Integers in an Array 查找数组中的最大元素,并删除包含该元素的所有行和列 - Find maximal elements in array and delete all lines and columns that contain it 打印出一个递归等于给定和的数组中的所有子集 - Print out all subsets in an array that equal an given sum recursively 递归打印数组中等于给定总和的所有子集 - Print all subsets in an array that equal to a given sum recursively
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM