检测整数是否可以写为给定整数的总和

时间:2009-12-05 00:36:22

标签: php algorithm

假设我有常数3,5,6,9,10。我怎样才能检测出如何将$ n作为输入写入,作为这些常数与最少数量项的总和?

实施例

$n=10, S=10
$n=18, S=9+9
$n=24, S=9+9+6
$n=27, S=9+9+9
$n=28, S=10+9+9

由于

7 个答案:

答案 0 :(得分:8)

这是另一个Python解决方案,但希望你很容易转换为PHP(我会自己做,但我不是PHP专家 - 我相信你可以做得更好)。我已经尝试过不使用任何高级Python函数,因此非Python读者更容易理解,但如果某些Python语法不清楚,请直接询问。

allowed = [3, 5, 6, 9, 10]
n = 28

solutions = [ None ] * (n + 1)
solutions[0] = []

for i in range(n + 1):
    if solutions[i] is None: continue
    for a in allowed:
        if i + a > n: continue
        if solutions[i + a] is None or len(solutions[i]) + 1 < len(solutions[i + a]):
            solutions[i + a] = solutions[i] + [a]

print solutions[28]

它的工作原理是从0开始并构建到所需的数字,保留到目前为止每个可能总数的最短解的缓存。它的运行时间为O(n * a),其中a是不同允许值的数量。

顺便说一句,你对n = 28的回答是错误的。它应该是[9,9,10]。

更新:这是我尝试PHP解决方案:

<?php
$allowed = array(3, 5, 6, 9, 10);
$n = 28;

$solutions = array();
$solutions[0] = array();

foreach (range(0, $n) as $i) {
    if (is_null($solutions[$i])) continue;
    foreach ($allowed as $a) {
        if ($i + $a > $n) continue;
        if (is_null($solutions[$i + $a]) ||
            sizeof($solutions[$i]) + 1 < sizeof($solutions[$i + $a])) {
            $solutions[$i + $a] = array_merge($solutions[$i], array($a));
        }
    }
}

var_dump($solutions[$n]);
?>

它提供了正确的答案,但请注意我不是专业的PHP编码器 - 我只是在PHP文档中查找了相应的函数。

答案 1 :(得分:2)

这是Mark Byers的算法,使用PHP开发人员更熟悉的循环结构重写,以及不会生成PHP通知的结构。 $C是您的整数集,$S解决方案。

$n = 28;
$C = array(3, 5, 6, 9, 10);
$S = array(array());

// if your set isn't sorted already, you have to call sort()
//sort($C);

for ($i = 0; $i <= $n; ++$i)
{
    if (!isset($S[$i]))
    {
        continue;
    }

    foreach ($C as $v)
    {
        if ($i + $v > $n)
        {
            break;
        }

        if (!isset($S[$i + $v])
         || count($S[$i + $v]) > 1 + count($S[$i]))
        {
            $S[$i + $v]   = $S[$i];
            $S[$i + $v][] = $v;
        }
    }
}

print_r($S[$n]);

答案 2 :(得分:0)

两种明显的方法表明自己:

  1. 写一系列线性方程, 并寻求各种解决方案。 选择数量最少的一个 条款。
  2. 试错,开始 首先是最大的术语。

答案 3 :(得分:0)

找到“S = 3A + 5B + 6C + 9D + 10E”的所有可能解决方案,然后选择A,B,C,D,E值最多的那个

答案 4 :(得分:0)

一个粗略的草图,一个不可扩展但正确的解决方案(对不起,到目前为止它唯一的python ..):

#!/usr/bin/env python
import itertools, sys

pool = [3, 5, 6, 9, 10]

repeat, found, solutions = 1, False, set()

try: x = int(sys.argv[1])
except: x = 42

while not found:    
    for n in itertools.product(pool, repeat=repeat):
        s = sum(n)
        if s == x:
            solutions.add(n)
            found = True
            break
    repeat = repeat + 1

print solutions

会产生:

$ python 1850629.py 11
set([(5, 6)])

$ python 1850629.py 19
set([(9, 10)])

$ python 1850629.py 21
set([(3, 9, 9)])

$ python 1850629.py 42
set([(3, 9, 10, 10, 10)])

答案 5 :(得分:0)

除了已经提供的优秀的一般答案之外,请记住,如果您的一组值具有某些属性,则存在更多最佳解决方案。

具体来说,如果您的解决方案是“最小” - 也就是说,任何值都存在一个最佳解决方案 - 那么您可以使用“贪婪”算法找到最少数量的元素:只需添加最大值,直到余数为小于它,重复下一个最大值,等等。

例如,在许多国家用于货币的面额是.01,。02,。05,。10,。20,。50,1,2,5 .......这套是最小的,所以你可以重复添加最大的有效面额。

答案 6 :(得分:-1)

NP完全问题

Subset sum problem