Php 检测整数是否可以写为给定整数的和
假设我有常数3,5,6,9,10。我如何检测如何将$n(输入)写入这些常量的总和,并且项数最少 例子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的解决方案一个不可缩放但
$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]);