簡體   English   中英

如何在PHP中優化此“彩票”功能?

[英]How can I optimize this 'lottery' function in PHP?

早些時候,我在Matlab中為此類彩票功能編寫了代碼,只是為了測試是否可行。 但是,實際上我在PHP中需要它,因此我只是重寫了代碼,它的確起作用了,但是由於涉及很多循環,因此我想確保自己盡可能高效地執行它。

代碼的作用是:

您可以調用函數$lotto -> type($users,$difficulty) ,它將返回兩個數字。 這就是解釋, $users是在網站上注冊的用戶數,即可能購買票的人。 $difficulty是介於1和10之間的數字,其中5是正常值,1是簡單值,而10是困難值。 這里的困難是指匹配彩票中的所有數字有多么困難。

那么函數返回的數字是多少? 那將是$n$r $n是彩票上的數字數量, $r是您可以從彩票中選擇的數字數量。 例如,在英國,如果您選擇6,則國家彩票有49個號碼,即$n = 49$r = 6

函數如何計算這兩個數字? 在英國國家彩票中,有13,983,816種可能的彩票組合。 如果我運行$lotto -> type(13983816,1) ,它將返回array(49,6) 基本上,它試圖做到這一點,因此,票證組合與注冊用戶一樣多。

tl; dr,代碼如下:

<?php
class lotto {
    public function type($users,$difficulty){
        $current_r = $r = 2;
        $current_n = 0;
        $difficulty = ($difficulty + 5) / 10; // sliding scale from 1 - 10
        $last_tickets_sold = 200; // tickets sold in last lotto
        $last_users = 100; // how many users there were in the last lotto
        $last_factor = $last_tickets_sold / $last_users; // tickets per user
        $factor = $last_factor * $difficulty;
        $users *= $factor;
        while($r <= 10){
            $u = 0;
            $n = $r;
            while($u < $users && $n < 50){
                $u = $this -> nCr(++$n,$r);
            }
            if($r == 2){
                $current_n = $n;
            } elseif(abs($this -> nCr($n,$r) - $users) < abs($this -> nCr($current_n,$current_r) - $users)){
                // this is a better match so update current n and r
                $current_r = $r;
                $current_n = $n;
            }
            $r++;
        }
        return array($current_n,$current_r);
    }
    private function nCr($n,$r){
        return $this -> factorial($n) / (
            $this -> factorial($r) * $this -> factorial($n - $r)
        );
    }
    private function factorial($x){
        $f = $x;
        while(--$x){
            $f *= $x;
        }
        return $f;
    }
}
$lotto = new lotto;
print_r($lotto -> type(1000,5));
?>

我進行了快速掃描,發現了一些可以進一步優化的地方。

組合
您的算法是蠻力的,可以進一步優化

private function nCr($n,$r){
    return $this -> factorial($n) / (
        $this->factorial($r) * $this->factorial($n - $r)
    );
}

function nCr($n,$r) {
    $top = 1;
    $sub = 1;

    for($i = $r+1; $i <= $n; $i++)
        $top *= $i;

    $n -= $r;
    for($i = 2; $i <= $n; $i++)
        $sub *= $i;

    return $top / $sub;
}

組合計算過多
計算組合是昂貴的。

$u = 0;
$n = $r;
while($u < $users && $n < 50){
    $u = $this -> nCr(++$n,$r);
}

$n = $r + 1;
$u = nCr($n, $r);

while ($u < $users && $n < 50) {
    $n++;
    $u *= $n;
    $u /= ($n - $r);
}

立即觀察到您有可能被0除以錯誤

$last_factor = $last_tickets_sold / $last_users;

可以通過在其周圍放一個簡單的if語句來解決

$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;

不管對代碼進行詳細檢查,您確定循環都不需要繼續或中斷嗎?

您的算法中factorial()的范圍是[0,50],那么為什么不靜態地對此進行預計算呢?

private static $factorial=array(1);

private static genFactorial($max) {
    if( count( self::$factorial ) > $max ) return;
    foreach ( range(count(self::$factorial), $max) as $n ) {
        self::$factorial[$n] = $i*self::$factorial[$n-1];
    }
}

現在添加一個self::genFactorial(50); __construct()type()並通過self::$factorial[$n]替換對$this -> factorial($n)的引用。

這只是一個快速的代碼轉儲。 甚至沒有檢查過編譯,因此不能原諒任何錯別字等。但這是通過數組元素提取來替換函數調用(包括while循環)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM