[英]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.