两个列表元素总和比较的最小复杂度

时间:2015-05-14 11:14:02

标签: c arrays algorithm

我对算法设计有一个关于数组的问题,应该用C语言实现。 假设我们有一个有n个元素的数组。为简单起见,n是{2}的幂,如1, 2, 4, 8, 16 , etc。我想用(n/2)元素将它分成两部分。分离条件为lowest absolute difference between sum of all elements in two arrays,例如,如果我有这个数组(9,2,5,3,6,1,4,7),它将与这些数组(9,5,1,3)(6,7,4,2)分开。第一个数组元素的总和是18,第二个数组元素的总和是19,差值是1,这两个数组是答案,但有两个数组,如(9,5,4,2)和{{1} }不是答案,因为元素求和的差异是(7,6,3,1),我们找到了4。所以1不是最小的差异。怎么解决这个? 谢谢。

1 个答案:

答案 0 :(得分:5)

这是Partition Problem,遗憾的是NP-Hard

但是,由于您的数字是整数,如果它们相对较低,则使用Dynamic Programming存在伪多项式O(W*n^2)解决方案(其中W是所有元素的总和)。

我们的想法是根据以下递归公式创建大小为(W/2+1)*(n+1)*(n/2+1)的DP矩阵:

D(0,i,0) = true
D(0,i,k) = false     k != 0
D(x,i,k) = false     x < 0
D(x,0,k) = false     x > 0
D(x,i,0) = false     x > 0
D(x,i,k) = D(x,i-1,k) OR D(x-arr[i], i-1,k-1)

上面给出了一个3d矩阵,其中每个条目D(x,i,k)表示是否有一个包含完全k个元素的子集,它们总和为x,并使用第一个i元素作为候选人。

获得此矩阵后,您只需找到最高x(小于SUM / 2),以便D(x,n,n/2) = true

稍后,你可以通过回到桌面上来获得相关的子集,并且&#34;回溯&#34;你在每一步的选择。 This thread讨论如何在一个非常类似的问题上完成。

对于小集合,还有一种天真的暴力解决方案的替代方案,它基本上将数组分割为所有可能的一半((2n)!/(n!*n!)),并从中挑选出最好的一半。