这是一个值得思考的大问题。在我的脑海中,这是我要使用的伪代码:
- A = 元素数组。
- A' = 已排序的元素数组。
- S = 所有元素的总和。
- 当 A' 不为空时:
- V = S 的整数部分。
- R = S 的余数 = S - floor(S)
- 制作 A', X 的临时副本。
- 从 X 的最大值到最小值迭代为 X[i]:
- 如果 X[i]
- 如果 R == 0,我们找到了解决方案。 V 是整数,X 包含加数。停止。
- 如果 X 为空,则无解。停止。
- 将 S 减去 A' 中的最大值。 S = S - Max(A')。从 A' 中删除 Max(A')。
- 返回到第 4 步。
当然,我必须看看这是否真的有效。这是我为测试它而编写的(非常杂乱、质量差的)代码:
<?php
$AA = $A = array(0.1, 0.2, 0.9, 0.5);
bcscale(8);
sort($AA, SORT_NUMERIC);
echo 'A = ' . implode(', ', $A), PHP_EOL;
echo 'A\' = ' . implode(', ', $AA), PHP_EOL;
$S = array_sum($AA);
echo 'S = ' . $S, PHP_EOL;
while (count($AA)) {
$V = floor($S);
echo 'V = ' . $V, PHP_EOL;
$R = bcsub($S, $V);
echo 'R = ' . $R, PHP_EOL;
$X = $AA;
$XX = array();
// Look for the largest value that is less than or equal to R.
for ($i = count($X) - 1; $i >= 0; $i--) {
echo 'X[i] = ' . $X[$i] . ', R = ' . $R, PHP_EOL;
$c = bccomp($X[$i], $R);
if ($c > 0) {
continue;
}
$XX[] = $X[$i];
$R = bcsub($R, $X[$i]);
unset($X[$i]);
if (bccomp($R, '0', strlen($R)) == 0) {
echo 'Largest whole number sum: ' . $V, PHP_EOL;
echo 'Elements: ' . implode(', ', $X), PHP_EOL;
break 2;
}
}
if (count($X) == 0) {
echo 'No sums to a whole number are possible.', PHP_EOL;
break;
}
$t = array_pop($AA);
$S = bcsub($S, $t);
}
echo 'S = ' . $S, PHP_EOL;
?>
这是一个丑陋的 O(N^2) 算法,但它应该是正确的。任何人都可以看到会失败的初始起始数组吗?
为了好玩,我尝试了一个包含 50 个元素的数组,将第一行替换为以下几行:
$A = array();
for ($i = 0; $i < 50; $i++) {
$A[] = mt_rand(1, 99) / 100.0;
}
$AA = $A;
乍一看,它看起来是正确的 - 我将把验证留给其他人;)