【问题标题】:Split array into half with equal or approximately equal array sum将数组分成两半,数组总和相等或近似相等
【发布时间】:2011-07-20 08:13:52
【问题描述】:

问题:

具有数值的数组需要以近似相等或可能相等的数组总和分成两半。数组中元素的数量或顺序并不重要。

$probabilites = array(0.4, 0.15, 0.1, 0.1, 0.2, 0.2, 0.3); # 1.45

$probabilites[0] = array(0.4, 0.15, 0.1, 0.1); # 0.75
$probabilites[1] = array(0.2, 0.2, 0.3); # 0.7 

有什么建议吗?

谢谢。

【问题讨论】:

  • 应该维持给定的顺序吗?是例如array(0.4, 0.15, 0.2)array(0.2, 0.1, 0.1, 0.3) 有效吗? (如果是,我想这会使事情复杂化。)
  • @jensgram,我写道这根本不重要,只有两个数组的总和应该尽可能接近。是的,它是有效的,我们不能将 7 个元素分成两半,4 + 3 将是理想的。 MarvinLabs,~= :) 您可以在示例中看到,0.75 接近 0.7,反之亦然。
  • 我的第一次尝试有一个很大的 YECK。

标签: php arrays


【解决方案1】:

像这样?

<?php
$in = array(0.4, 0.15, 0.1, 0.1, 0.2, 0.2, 0.3);

// Sort array decreasing
rsort($in, SORT_NUMERIC);

// Start with two empty arrays
$arr1 = $arr2 = array();

// Put the next value in the array in the array with the lowest sum
foreach ($in as $value)
  if (array_sum($arr2) > array_sum($arr1)) $arr1[] = $value; else $arr2[] = $value;

// Wrap in array (as in question)
$out = array($arr1,$arr2);

【讨论】:

  • 等待 30 秒以接受正确答案。我必须说非常聪明:)
  • 如果值彼此相差很大,这将无法正常工作(尽管如果它们接近就可以了)。顺便说一句,这是非常著名的背包问题。
  • 我已经测试了几次,它按预期工作..pokit.etf.ba/get/500b563910d333cd07739b48a4256c38.png
  • 一个例子是 (10, 0, -100)。
  • @pelle-ten-cate 100,50,15,15,15,15,15,15,15,15,15,15 无法以最佳方式工作。你应该可以在每个盒子里放 150,但是这个算法在一个盒子里放 145,在另一个盒子里放 155。这是背包问题,它是 NP-Complete 是有原因的。 (取所有数字的总和,然后除以 2 - 这就是背包的大小。)
【解决方案2】:

你知道这是http://en.wikipedia.org/wiki/Knapsack_problem吗?

而且它是 NP-Complete,所以你不能快速完成。

对于一个小列表,它不会太糟糕,如果你有一个更大的列表,请参阅维基百科页面上的一些解决方案。

【讨论】:

  • 谢谢你的链接,基本上就是这样,数组不会有超过几十个数组总和为1的值。
【解决方案3】:

尝试以下方法:

从一个空数组 A 和给定的数组 B 开始(在您的示例中为 $probabilities):

  • 删除 B 的第一个元素并将其附加到 A。
  • 计算两个数组的总和并计算差值。
  • 重复此操作,直到差异变得更糟。
  • 当差异变得更糟(即更大)时,反转最后一步,您就完成了。

或者为了节省时间:

  • 首先计算 B = sum0 的和。
  • 删除 B 的第一个元素并将其附加到 A。
  • 将 sum (a) 与 sum0/2 进行比较。
  • 重复直到情况变得更糟,然后逆转最后一步。

【讨论】:

  • 不,这并不总是有效。想象一下这些值是 0.1、0.1、0.1、10、0.1、0.1、0.1。最好的办法是将 10 放在一个数组中,将所有 6 个 0.1 条目放在另一个数组中。您的算法将在数组 1 中得到 0.1、0.1、0.1,在数组 2 中得到 10、0.1、0.1、0.1。
  • 由于 OP 保持了原始数组的顺序,所以我按照他的例子。
  • 感谢您的意见,我确实尝试过类似的方法,但我确信还有其他方法,Pelle ten Cate 提供了非常好的解决方案。我对订单感到抱歉,那只是巧合。再次感谢您。
  • 好吧,我想,如果只是为了示例,我会手动进行。将 TS 归功于我同意这一点,我认为其他数字列表也会出现。 :)
  • 是的,你的方法肯定比我的更复杂,并且产生更好的分割。除非你得到一个像 (2, 3, -5) 这样的数组。这将产生(2,-5)和(3)。但我的方法也会因该输入而失败。
【解决方案4】:

也许对数组进行排序,从最大值开始。将另一个值放入总和较小的 2 个数组之一。任何人都可以检查此解决方案吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-19
    • 2015-11-16
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    相关资源
    最近更新 更多