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

发布于 2024-12-08 06:55:40 字数 857 浏览 0 评论 0原文

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


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


这是我的想法:

假设我们交换 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;
            }
        }
    }
}

但是,有没有人有更好的解决方案 ?如果你得到了,请告诉我,我将非常感激你!

I am hunting job now and doing many algorithm exercises. Here is my problem:


Given two arrays: a and b with same length, the subject is to make |sum(a)-sum(b)| minimal, by swapping elements between a and b.


Here is my though:

assume we swap a[i] and b[j], set Delt = sum(a) - sum(b), x = a[i]-b[j]
then Delt2 = sum(a)-a[i]+b[j] - (sum(b)-b[j]+a[i]) = Delt - 2*x,
then the change = |Delt| - |Delt2|, which is proportional to |Delt|^2 - |Delt2|^2 = 4*x*(Delt-x),

Based on the thought above I got the following code:


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;
            }
        }
    }
}

However, does anybody have a much better solution ? If you got, please tell me and I would be very grateful of you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巴黎夜雨 2024-12-15 06:55:40

这个问题基本上是分区问题的优化问题,具有相等部分的额外约束。我将证明添加这个约束并不会让问题变得更容易。

NP-Hardness 证明:

假设有一个算法A可以在多项式时间内解决这个问题,我们可以解决多项式时间内的划分问题

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< /code>,算法将得出 true。

如果算法返回 true,并且迭代 k,我们就有两个数组:S2、S1,具有相同的元素数量和相等的值。通过从数组中删除 k 个零,我们得到了原始 S 的一个分区,因此 S 有了一个分区。

多项式:

假设A需要P(n)时间,我们生成的算法将需要n*P(n)时间,这也是多项式。

结论:

如果这个问题可以在多项式时间内解决,那么分区问题也可以在多项式时间内解决,因此 P=NP。基于此:这个问题是NP-Hard问题。

因为这个问题是 NP-Hard,所以为了获得精确的解决方案,您可能需要指数算法。其中之一是简单的回溯 [我将其作为练习留给读者来实现回溯解决方案]

编辑:正如@jpalecek所提到的:通过简单地创建一个归约:S->S+(0,0,...,0) [k乘以0] , 可以直接证明NP-还原硬度。多项式是微不足道的,正确性与上述分区的正确性证明非常相似:[如果存在分区,则可以添加“平衡”零;另一个方向只是修剪那些零]

This problem is basically the optimization problem for Partition Problem with an extra constraint of equal parts. I'll prove that adding this constraint doesn't make the problem easier.

NP-Hardness proof:

Assume there was an algorithm A that solves this problem in polynomial time, we can solve the Partition-Problem in polynomial time.

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

Correctness:

If there is a partition denote as (S1,S2) [assume S2 has more elements], on iteration |S2|-|S1| [i.e. when adding |S2|-|S1| zeros]. The input to A will contatin enough zeros so we can return two equal length arrays: S2,S1+{0,0,...,0}, which will be a partition to S, and the algorithm will yield true.

If the algorithm yields true, and iteration k, we had two arrays: S2,S1, with same number of elements, and equal values. by removing k zeros from the arrays, we get a partition to the original S, so S had a partition.

Polynomial:

assume A takes P(n) time, the algorithm we produced will take n*P(n) time, which is also polynomial.

Conclusion:

If this problem is solveable in polynomial time, so does the Partion-Problem, and thus P=NP. based on this: this problem is NP-Hard.

Because this problem is NP-Hard, for an exact solution you will probably need an exponential algorith. One of those is simple backtracking [I leave it as an exercise to the reader to implement a backtracking solution]

EDIT: as mentioned by @jpalecek: by simply creating a reduction: S->S+(0,0,...,0) [k times 0], one can directly prove NP-Hardness by reduction. polynomial is trivial and correctness is very similar to the above partion's correctness proof: [if there is a partition, adding 'balancing' zeros is possible; the other direction is simply trimming those zeros]

贪恋 2024-12-15 06:55:40

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

我无法在脑海中做到这一点,但我很确定有一个建设性的解决方案。我认为如果你先对它们进行排序,然后根据某种规则进行处理。类似的东西 If value > 0 并且如果 sum(a)>sum(b) 则插入 a else into b

Just a comment. Through all this swapping you can basically arrange the contents of both arrays as you like. So it is unimportant in which array the values are at start.

Can't do it in my head but I'm pretty sure there is a constructive solution. I think if you sort them first and then deal them according to some rule. Something along the lines If value > 0 and if sum(a)>sum(b) then insert to a else into b

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文