算法 - 找到两个数组之和的最小减法

时间:2011-10-02 08:29:16

标签: optimization language-agnostic

我现在正在找工作并做很多算法练习。这是我的问题:


给定两个数组: a b 具有相同的长度,主题是| sum(a)-sum(b)|最小化,通过交换 a b 之间的元素。


这是我的:

假设我们交换a [i]和b [j],设置Delt = sum(a) - sum(b),x = a [i] -b [j]
然后Delt2 = sum(a)-a [i] + b [j] - (sum(b)-b [j] + a [i])= Delt - 2 * x,
那么改变 = | Delt | - | Delt2 |,与| Delt | ^ 2成比例 - | Delt2 | ^ 2 = 4 * x *(Delt-x),

根据上面的想法,我得到了以下代码:


Delt = sum(a) - sum(b);
done = false;
while(!done)
{
    done = true;
    for i = [0, n)
    { 
        for j = [0,n)
        {
            x = a[i]-b[j];
            change = x*(Delt-x);
            if(change >0)
            {
                 swap(a[i], b[j]);
                 Delt = Delt - 2*x;
                 done = false;
            }
        }
    }
}

但是,有没有人有更好的解决方案?如果你有,请告诉我,我会非常感谢你!

2 个答案:

答案 0 :(得分:3)

这个问题基本上是Partition Problem的优化问题,具有相等部分的额外约束。我将证明添加此约束不会使问题更容易。

NP-Hardness证明:
假设有一个算法A可以在多项式时间内解决这个问题,我们可以在多项式时间内求解Partition-Problem

Partition(S):
for i in range(|S|):
   S += {0}
   result <- A(S\2,S\2) //arbitrary split S into 2 parts
   if result is a partition: //simple to check, since partition is NP.
     return true.
return false //no partition

<强>正确性:
如果有一个分区表示为(S1,S2)[假设S2有更多元素],则迭代| S2 | - | S1 | [即添加| S2 | - | S1 |时零。 A的输入将包含足够的零,因此我们可以返回两个相等长度的数组:S2,S1 + {0,0,...,0},这将是S的分区,并且算法将产生真实。
如果算法产生真,并且迭代k,我们有两个数组:S2,S1,具有相同数量的元素,并且值相等。通过从数组中删除k个零,我们得到原始S的分区,因此S有一个分区。

<强>多项式:
假设A花费P(n)时间,我们生成的算法将花费n*P(n)时间,这也是多项式。

<强>结论:
如果这个问题在多项式时间内是可解的,那么Partion-Problem也是如此,因此P = NP。基于此:这个问题是NP-Hard。

因为这个问题是NP-Hard,所以对于一个精确的解决方案,您可能需要一个指数算法。其中一个很简单backtracking [我把它作为练习留给读者实施回溯解决方案]

编辑:正如@jpalecek所提到的:只需创建一个缩减:S->S+(0,0,...,0) [k乘以0],就可以通过缩减直接证明NP-Hardness。多项式是微不足道的,正确性非常类似于上面的部分的正确性证明:[如果有一个分区,添加'平衡'零是可能的;另一个方向就是修剪那些零]

答案 1 :(得分:0)

只是评论。通过所有这些交换,您基本上可以根据需要排列两个数组的内容。因此,值在哪个数组中是不重要的。

无法做到这一点,但我很确定有一个建设性的解决方案。我想如果你先把它们排序然后按照一些规则来处理它们。行If value > 0 and if sum(a)>sum(b) then insert to a else into b