当前位置: 首页 > 知识库问答 >
问题:

分区问题 - 使用最小内存查找集合的元素

西门高歌
2023-03-14

我必须使用动态编程来解决一个经典的分区问题。我有一个正整数数组作为输入,其中n是整数的个数,s是这些整数的和,我需要找到两个集合之间的最小差,这两个集合可以使用输入中的元素来构造。我还需要输出一个与input array大小相同的名为“ownership”的布尔数组,它提供了元素属于第一个还是第二个最优集合的信息。例如,如果所有权数组中的第I个值为真,则输入数组的第I个元素属于第一个集合。

我的程序使用自下而上的方法找到最小差异。该任务要求程序的内存复杂度为 θ(s),因此我只使用该数组的两行,而不是像经典方法那样使用大小为 n*s 的 2D 数组。在第一行中,我保留上一个已处理的行,因此我可以根据前面的解决方案填充第二行。

问题是,通过这种内存优化,我不确定应该如何填充所有权数组。

我知道可以使用n*s数组中的回溯来检索集合元素。然而,由于任务限制,我无法使用该方法,我不知道如何有效地构建所有权表。

有没有办法有效地找到哪些元素属于这两个最优集合中的哪一个,在自下而上的方法中,内存复杂度θ(s)和时间复杂度O(n*s)的约束?

我当前的C#代码:

 public int SetsMinimum(int[] tab, out bool[] ownership)
 {
    int n = tab.Length;
    int sum = 0;
    foreach (int v in tab) sum += v;
    ownership = new bool[n];
    bool[,] dp = new bool[2, sum + 1];
    int min = sum;
    dp[0, 0] = true;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= sum; j++)
        {
            dp[1,j] = dp[0,j];
            if (j - tab[i - 1]>=0)
            {
                dp[1, j] = dp[0, j - tab[i - 1]];
            }     
        }
        for(int j=0;j<sum;j++)
        {
            if (dp[1, j])
            {
                int cMin = Math.Abs((sum - j) - j);
                if (min>cMin)
                {
                    min = cMin;
                }
            }    
            dp[0, j] = dp[1, j];
        }
    }
    return min;
}

共有2个答案

邢令
2023-03-14

我昨天找到了一个解决方案

  1. 初始化另一个和1元素数组并用零填充它。
  2. 在dp数组上迭代时,保存第一个元素的先前数组索引,它允许实现每个总和。例如,对于{4,3,2},您可以在使用第二个元素时实现总和7,并且您可以使用第一个元素获得4的总和。
  3. 得到最小差值后,选择最优集和之一,要么(sum-min)/2,要么Sum-((sum-min)/2)
  4. 跳转到索引数组中的和,在索引数组中指向的索引中将所有权数组设置为true,然后将元素从和中减去。重复直到总和为零。

这种方法只会选择必要的元素来构造集合总和中的任何一个,并且它将在 O(n*s) 时间内工作,因为索引数组可以在自下而上的方法中填充。

郎伟兆
2023-03-14

您可以编写一个在内存< code>O(s)中运行的函数,该函数运行一次DP并找出最接近的目标和。

您可以编写一个在内存 O 中运行的函数,该函数运行一次 DP,并找出所有权数组中的最后一个值是真还是假才能达到该目标总和。

重复运行第二个函数,从末尾到前面挑选出所有权数组的每个成员。

这将占用内存 O(s) 和时间 O(s * n^2)。(因为您运行了 n 个 DP。与通常的DP方法相反,该方法需要内存O(s * n)和时间O(s * n)。

 类似资料:
  • 我有一组向量,我需要用java编写算法,找到这个集合的最小元素。问题是,有些元素是无与伦比的。例如minset{(1,4,6),(3,2,5),(2,3,4),(5,4,6)} = {(1,4,6),(3,2,5),(2,3,4)}。对于最小元素集“minset”,以下内容成立:原始集的每个向量要么在“minset”中,要么在“minset”中

  • 本文向大家介绍JavaScript 查找最小或最大元素,包括了JavaScript 查找最小或最大元素的使用技巧和注意事项,需要的朋友参考一下 示例 如果您的数组或类似数组的对象是numeric,也就是说,如果它的所有元素都是数字,则可以使用Math.min.apply或作为第一个参数Math.max.apply传递null,而将数组作为第二个参数传递。 6 在ES6中,可以使用...运算符扩展数

  • 我正在研究最小堆实现,对这个概念非常陌生。 以此作为参考:< br > https://www.geeksforgeeks.org/building-heap-from-array/ https://algorithm tutor . com/Data-Structures/Tree/Binary-Heaps/ 我修改了代码并想出了: (这是我遇到问题的代码,所有其他代码都与我的问题无关,至少我是

  • 假设有几个数组: 我需要找出所有可能的元素集合(1,2,3,4,5...)中的每一个在至少两个阵列(A,B,C....)并以下列方式显示它们: 实际输入是包含字符串的文件。可能有数千个文件,每个文件可能包含一百多个密钥字符串。 我尝试了下面的方法:首先,我通过比较所有可能的数组对来生成元素集。然后,我试图通过使用逻辑生成其他集合——元素集合的交集在数组集合的并集中很常见。像这样: 从上面我们可以得

  • 我试图找到最小的整数中的只是使用两个简单的循环。我最初尝试了一个循环,但是它没有正确更新。我还没有学习,所以这应该在不使用任何代码的情况下完成。 这就是我所拥有的: 我的最小值似乎总是列表中的最后一个值,所以我尝试打印以查看发生了什么,它似乎会更新不同的值,最后更新最后一个值。我不知道为什么会这样。 这是它正在打印的内容,例如:

  • 问题 怎样从一个集合中获得最大或者最小的 N 个元素列表? 解决方案 heapq 模块有两个函数:nlargest() 和 nsmallest() 可以完美解决这个问题。 import heapq nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] print(heapq.nlargest(3, nums)) # Prints [42, 37, 23] p