之前我在Matlab中为这种彩票功能编写了一个代码,只是为了测试它是否可行。但是,我实际上需要在PHP中使用它,所以我只是重写了代码,它似乎确实有效,但由于它涉及大量循环,我想确保我尽可能高效地进行。
代码的作用:
您可以调用函数$lotto -> type($users,$difficulty)
,它将返回两个数字。以下是解释,$users
是在网站上注册的用户数量,即可能购买机票的用户数量。 $difficulty
是1到10之间的数字,其中5表示正常,1表示容易,10表示很难。这里的难度意味着匹配彩票上的所有数字是多么困难。
那么函数返回的数字是多少?那将是$n
和$r
。 $n
是彩票上的号码数量,$r
是您可以从彩票中选择的号码数量。例如,在英国,国家彩票有49个数字,如果您选择6. I.e $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));
?>
答案 0 :(得分:2)
我做了一个快速扫描,发现了一些可以进一步优化的地方。
组合
您的算法是一个强力的算法,可以进一步优化
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);
}
答案 1 :(得分:1)
立即观察到你有可能除以0错误
$last_factor = $last_tickets_sold / $last_users;
可以通过在其周围添加一个简单的if语句来解决
$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;
答案 2 :(得分:0)
无论是对您的代码进行详细检查,您确定您的循环不需要继续或中断吗?
答案 3 :(得分:0)
算法中 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()
,并将$this -> factorial($n)
的引用替换为self::$factorial[$n]
。
这只是一个快速的代码转储;甚至没有编译检查所以原谅任何拼写错误等,但这样做的是用数组元素fetch替换函数调用(包括while循环)。