具有最小差异的两个子集

问题描述

考虑数组arr

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

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

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

例如,如果arr[] = [0,1,5,6],则最小差异为0,而我的两个子集为s1[] = [0,5] s2[] = [6]

一个示例可能是arr[] = [16,14,13,12,10,9,3],两个子集分别是s1[]=[16,3]s2[] = [14,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>=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 < s2,所以s1的值只能在0..(sum_arr/2)之间

我的目标是将sum_arr - 2*s1的最小值设为最小,而对于最大的s1则为真

解决方法

使整数T[][]的并行表具有与go[][]相同的维数

当您在此处做出决定

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

输入T[i][j]的某种信息,指向true的{​​{1}}前体坐标

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