问题陈述:
给定一个数组,任务是将其分成两个集合S1和S2,使得它们的和之间的绝对差最小。
样本输入,
[1,6,5,11]
=〉1
。两个子集是{1,5,6}
和{11}
,和是12
和11
。因此答案是1
。[36,7,46,40]
=〉23
。两个子集是{7,46}
和{36,40}
,和是53
和76
。因此答案是23
。
限制
1〈=数组大小〈= 50
1〈= a[i]〈= 50
我的努力:
int someFunction(int n, int *arr) {
qsort(arr, n, sizeof(int), compare);// sorted it for simplicity
int i, j;
int dp[55][3000]; // sum of the array won't go beyond 3000 and size of array is less than or equal to 50(for the rows)
// initialize
for (i = 0; i < 55; ++i) {
for (j = 0; j < 3000; ++j)
dp[i][j] = 0;
}
int sum = 0;
for (i = 0; i < n; ++i)
sum += arr[i];
for (i = 0; i < n; ++i) {
for (j = 0; j <= sum; ++j) {
dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
if (j >= arr[i])
dp[i + 1][j + 1] = max(dp[i + 1][j + 1], arr[i] + dp[i][j + 1 - arr[i]]);
}
}
for (i = 0; i < n; ++i) {
for (j = 0; j <= sum; ++j)
printf("%d ", dp[i + 1][j + 1]);
printf("\n");
}
return 0;// irrelevant for now as I am yet to understand what to do next to get the minimum.
}
输出
假设对于输入[1,5,6,11]
,我得到dp
数组输出如下。
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 12 12 12 12 12 12 12 12
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 16 17 18 18 18 18 22 23
现在,如何决定这两个子集以获得最小值?
我已经看过这个link,但是对于像我这样的DP初学者来说,解释还不够好。
3条答案
按热度按时间1zmg4dgp1#
您必须为
SumValue = OverallSum / 2
解决subset sum
问题请注意,您不需要解决任何优化问题(正如在代码中使用
max
操作所揭示的那样)。只需用可能的和填充大小为(SumValue + 1)的线性表(1D数组
A
),获得最接近最后一个单元格的非零结果(向后扫描A)wint索引M
,并将最终结果计算为abs(OverallSum - M - M)
。首先,将第0个条目设置为1。然后,对于每个源数组项
D[i]
,从末尾到开头扫描数组A
:例如
D = [1,6,5,11]
,您有SumValue = 12
,使数组A[13]
,并计算可能的总和工作Python代码:
bvhaajcl2#
相同的Java代码
vq8itlhq3#
如果有人感兴趣的话,我会写一些Java代码,但想法和@MBo的回答一样