Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 检测整数是否可以写为给定整数的和_Php_Algorithm - Fatal编程技术网

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

Php 检测整数是否可以写为给定整数的和,php,algorithm,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 谢谢有两种明显的方法: 写出一系列线性方程组, 解决问题,找到各种解决方案。 选择数量最少的一个 条件 试错,开始 以最大条款为先 找到“S=3A+5B+6C+9D+10E”的所有可能解决方案,然后选择A、B、C、D、E值最多为0的解决方案一个不可缩放但

假设我有常数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

谢谢

有两种明显的方法:

  • 写出一系列线性方程组, 解决问题,找到各种解决方案。 选择数量最少的一个 条件
  • 试错,开始 以最大条款为先

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

    一个不可缩放但正确的解决方案的草图(抱歉,目前为止它是唯一的python..):

    将产生:

    $ 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)])
    

    这是另一个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]
    
    allowed=[3,5,6,9,10]
    n=28
    解决方案=[None]*(n+1)
    解决方案[0]=[]
    对于范围(n+1)内的i:
    如果解决方案[i]为无:继续
    对于允许的输入:
    如果i+a>n:继续
    如果解[i+a]为无或len(解[i])+1
    它的工作原理是从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文档中查找了等效函数。

    这是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]);
    
    $n=28;
    $C=数组(3,5,6,9,10);
    $S=数组(array());
    //如果集合尚未排序,则必须调用sort()
    //分类(丙元);;
    对于($i=0;$i$n)
    {
    打破
    }
    如果(!isset($S[$i+$v])
    ||计数($S[$i+$v])>1+计数($S[$i]))
    {
    $S[$i+$v]=$S[$i];
    $S[$i+$v][]=$v;
    }
    }
    }
    印刷品($S[$n]);
    
    NP完全问题


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

    具体地说,如果您的解决方案是“最小”的,即任何值都存在一个最佳解决方案,那么您可以使用“贪婪”算法找到最小数量的元素:只需添加最大值,直到余数小于它,然后重复下一个最大值,依此类推


    例如,许多国家的货币面额为.01、.02、.05、.10、.20、.50、1、2、5、。。。。此集合是最小的,因此您可以重复添加最大的有效面额。

    到目前为止,您对解决方案有什么想法?你被困在哪里了?这也应该被标记为家庭作业吗?我考虑过从最大值到最小值重复划分,如果最后我得到了剩余的0,那么它可以被写为堆栈上的数字之和。然而,这不是一个好方法,例如$n=17。它会说17=10+6,余数1。正确的解决方案应该是S=6+6+5不,这不是家庭作业。我只是把我的问题简单得太好了,似乎只有一个:)事实上,这是一个通过短信的在线支付系统。那么不能用这些常量的总和来表示的输入值呢?0,1,2,4,7,11,…?贴子被标记为
    PHP
    ,正如你所知:)在我的TZ中已经太晚了。。应该在看书(我想是在睡觉吧)很好,我会尽力消化它,最终接受你的解决方案。斯凯奇:我尝试过将它转换成PHP。看我更新的答案。这是一个很好的,简短的和简单的算法。我已经重新发布了一个经过清理的PHP实现,更符合PHP的习惯用法。实际上,您想要一个最小化
    a+B+C+D+E
    的解决方案。这不一定是在有最多零值的。。。是吗?是的。原问题的正确关键词是“求解线性丢番图方程”。这是一个重要的研究领域,算法也不平凡。例如:@Stephen我想你误读了这个问题,他想要尽可能少的术语,因此他想要的是最多的零。顺便说一句,我最初没有提到它,但是如果你按照升序对整数集排序,你可以提前退出内部循环,而不是迭代所有可能的组合。我已经相应地更新了上面的代码片段。
    $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]);