我现在正在找工作并做很多算法练习。这是我的问题:
给定两个数组: 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;
}
}
}
}
但是,有没有人有更好的解决方案?如果你有,请告诉我,我会非常感谢你!
答案 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