问题陈述:
给定一个数组,任务是将其分为两组S1和S2,以使它们的和之间的绝对差最小。
采样输入 ,
[1,6,5,11]=> 1。2个子集为{1,5,6}和{11},总和为12和11。因此答案是1。
[1,6,5,11]
1
{1,5,6}
{11}
12
11
[36,7,46,40]=> 23。2个子集为{7,46}和{36,40},总和为53和76。因此答案是23。
[36,7,46,40]
23
{7,46}
{36,40}
53
76
约束条件
1 <=数组大小<= 50 1 <= a [i] <= 50
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. }
输出值
假设对于input [1,5,6,11],我得到的dp数组输出如下。
[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
现在,如何 确定 2个子集以获得最小值?
PS-我已经看过此链接,但是对于像我这样的DP初学者来说,解释还不够好。
你必须解决subset sum问题SumValue = OverallSum / 2
subset sum
SumValue = OverallSum / 2
请注意,您不需要解决任何优化问题(如max在代码中使用操作所揭示的)。
max
只需A用可能的总和填充大小为(SumValue + 1)的线性表(1D数组),获得最接近最后一个单元格非零结果(向后扫描A)的wint索引,M并将最终结果计算为 abs(OverallSum - M - M)。
A
M
abs(OverallSum - M - M)
首先,将第0个条目设置为1。然后从头到尾对每个源数组项D[i]扫描数组A:
D[i]
A[0] = 1; for (i = 0; i < D.Length(); i++) { for (j = SumValue; j >= D[i]; j--) { if (A[j - D[i]] == 1) // we can compose sum j from D[i] and previously made sum A[j] = 1; } }
例如,D = [1,6,5,11]您拥有SumValue = 12,制作数组A[13]并计算可能的总和
D = [1,6,5,11]
SumValue = 12
A[13]
A array after filling: [0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1]
工作的Python代码:
def besthalf(d): s = sum(d) half = s // 2 a = [1] + [0] * half for v in d: for j in range(half, v - 1, -1): if (a[j -v] == 1): a[j] = 1 for j in range(half, 0, -1): if (a[j] == 1): m = j break return(s - 2 * m) print(besthalf([1,5,6,11])) print(besthalf([1,1,1,50])) >>1 >>47