[英]Write a faster combinatorics algorithm
我正在尝试编写一个组合算法,以获得n
中k
所有可能组合而不重复。
公式是:
n!/(k!(n-k)!));
结果以数组结尾。 我实际写的是这样的:
function Factorial($x)
{
if ($x < 1)
{
echo "Factorial() Error: Number too small!";
)
$ans = 1;
for ($xx = 2; $xx >= $x; $xx++)
{
$ans = $ans * $xx;
}
return($ans);
}
function Combination($selectcount,$availablecount)
{
$ans = Factorial($availablecount) / (
Factorial($availablecount - $selectcount) * Factorial($selectcount)
);
return ($ans);
}
这是实现这一目标的最快方法吗? 有没有办法加快速度? 也许以递归方式写出来?
我认为问题是计算C(n,k),这可以在不计算阶乘的情况下完成,诀窍是首先要注意
C(n,k) = (n*(n-1)...(n-k+1)) / (1*2*...*k) = (n/1)*(n-1/2)*...(n-k+1/k)
也为了效率
C(n,k) = C(n,n-k), therefore choose which ever is smaller k or n-k
如果有错误,请随意编辑,因为我已经从C转换它,我不知道PHP
function nCk($n, $k)
{
if( $n-$k<$k )
$k = $n-$k;
$ans = 1;
for( $i=1; $i<=$k; ++$i )
{
$ans = ($ans*($n-$i+1))/$i;
}
return $ans;
}
IMO不值得优化,除非由于浮点限制而使用HEAVY:170! = 7.257415615308E + 306,下一个阶乘(171!)超出浮点范围。 我猜这个递归会减慢进程(但没有测试过)。
function Factorial($x)
{
if ($x < 1)
{
echo "Factorial() Error: Number too small!";
}
那是错的, 0! = 1
定义了0! = 1
,因此测试应该是$x < 0
。
$ans = 1;
for ($xx = 2; $xx >= $x; $xx++)
你错了条件,它必须是$xx <= $x
。
function Combination($selectcount,$availablecount)
{
$ans = Factorial($availablecount) / (
Factorial($availablecount - $selectcount) * Factorial($selectcount)
);
return ($ans);
}
你有两个潜在的问题,
Factorial
函数比在这里计算组合计数的循环要慢 这些是否是实际问题取决于您的应用。 你写道,结果最终是一个数组,大概是为了避免重新计算,所以初始计算的速度不那么重要。 但是,溢出问题可能很好。 为了避免这些,按照Pascal三角形递归计算数组条目, choose(n+1,k) = choose(n,k) + choose(n,k-1)
,其中如果k < 0
choose(n,k) = 0
k < 0
或k > n
。 或者,您可以计算以choose(n,0) = 1
开头的每一行choose(n,0) = 1
并choose(n,k) = choose(n,k-1)*(n+1-k)/k
为1 <= k <= n
。 两种方法都避免了大的中间n!
从而为更广泛的数字提供准确的结果。
这是我设法获得阶乘循环的最快速度:
function Factorial($factVal) {
if ($factVal < 0) {
die("Factorial() Error: Number too small!");
}
$factorial = 1;
while ($factVal > 1) {
$factorial *= $factVal--;
}
return $factorial ;
}
您实际上不需要计算完整的分子和分母。 例如:
C(7,2) = 7! / (2! * (7-2)!) = 7! / (2! * 5!) = (7 * 6) / (2 * 1)
也就是说,分母中的最大因子取消了分子的阶乘的最低部分。 所以,例如,如果k> n / 2,你需要做的就是将数字从k + 1乘以n然后除以(nk)! 这节省了相当于计算全因子的大量工作。
这是这种方法的草案:
function Combination($selectcount,$availablecount)
{
$remainder = $availablecount - $selectcount;
if ($remainder > $selectcount) {
$tmp = $remainder;
$remainder = $selectcount;
$selectcount = $tmp;
}
$ans = 1;
while ($availablecount > $selectcount) {
$ans *= $availablecount;
$availablecount--;
}
while ($remainder > 1) {
$ans /= $remainder;
$remainder--;
}
return ($ans);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.