【问题标题】:Two subsets with minimum difference [closed]差异最小的两个子集[关闭]
【发布时间】:2020-12-11 03:03:46
【问题描述】:

考虑一个数组arr

s1s2 是我们原始数组 arr 的任意两个子集。我们应该对原始数组进行分区,使这两个子集具有最小差异,即min(sum(s1) - sum(s2)),其中sum(s1) >= sum(s2)

我应该打印这两个子集,即s1s2,作为我的输出。

您可以将这些子集存储在向量中。

例如如果arr[] = [0,1,5,6],那么最小的区别是0,我的两个子集是s1[] = [0,1,5] s2[] = [6]

另一个例子可以是arr[] = [16,14,13,13,12,10,9,3],两个子集是s1[]=[16,13,13,3]s2[] = [14,12,10,9],最小差值又是0

我似乎不知道如何到达这两个子集。

非常感谢!

注意:我知道如何使用 DP 获得两个子集的最小差异,但我无法继续进行。它得到了我无法做到的两个子集(差异很小)。 只需一个沿着正确方向轻推的算法就可以了。

#include<iostream>
#include<vector>
using namespace std;

int min_subset_sum_diff(int a[], int n,int sum) {
    vector<vector<bool>> go(n + 1, vector<bool>(sum + 1, false));
    for (int i = 0; i < n + 1; ++i) {
        go[i][0] = true;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= sum; ++j) {
            if (a[i - 1] <= j) {
                go[i][j] = go[i - 1][j - a[i - 1]] || go[i - 1][j];
            }
            else {
                go[i][j] = go[i - 1][j];
            }
        }
    }
    for (int j = (sum / 2); j >= 0; --j) {  
        if (go[n][j]) {                  // only need the last row as I need all the elements, which is n
            return sum - 2 * j;
        }
    }
    return INT_MAX;
}

int main() {
    int a[] = { 3,100,4,4 };
    int n = sizeof(a) / sizeof(a[0]);
    int sum = 0;
    for (auto i : a) {
        sum += i;
    }
    cout << min_subset_sum_diff(a, n,sum);
}
s1 = sum(first_subset)

s2= sum(second_subset)

假设s2&gt;=s1

s1 + s2 = sum_arr
s2 = sum_arr - s1       //using this in the next equation
s2-s1 = difference
(sum_arr - s1) - s1 = difference 
sum_arr - 2*s1 = difference

这是我的基本逻辑。

sum(s1)sum(s2) 介于 0..sum_arr 之间

由于我假设s1 &lt; s2,s1 的值只能在0..(sum_arr/2) 之间

我的目标是sum_arr - 2*s1 的最小值,这对于最大的s1 来说是正确的

【问题讨论】:

  • 如果您知道如何通过 DP 获得最小差异,您只需要记住分区以及您计算的最小差异
  • @user123456 可能是因为看起来可能是家庭作业,以前有人问过,像geeksforgeeks.org/… 这样的解决方案很容易通过 Google 搜索。
  • 这实际上是一个技术性的 F2F 面试问题。而且我还没有找到任何将数组实际划分为两个子数组的解决方案。所有解决方案仅输出最小差异。在这里问之前我做了研究。
  • @user123456 请参阅stackoverflow.com/a/63362010/585411 了解我对此问题的变体的解决方案。 (找到总和为给定总和的所有固定大小的子集。没有重复。)如果你能理解我在那里使用链表的方式,那么解决这个问题应该很容易。当然,它只会输出总和为二分之一的集合,您必须返回并找出该集合的补码。
  • 你不应该问问题,删除它,因为你不喜欢 cmets 并在一小时后问完全相同的问题。

标签: c++ arrays algorithm subset dynamic-programming


【解决方案1】:

制作与go[][]相同维度的int T[][]的并行表

当你在这里做出决定时

if (a[i - 1] <= j) 

输入T[i][j]某种指向truego[i][j]的前体坐标的信息

填写表格后,您在布尔表的go[n] 行中搜索最佳true 条目。找到后,从T 表的同一个单元格中获取值并跟随到前体,然后到前体的前体,依此类推(“展开”子集信息)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-11
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    相关资源
    最近更新 更多