rolaka 发表于 2010-5-1 13:49:59

关于依照表取得随机值的问题

本帖最后由 rolaka 于 2010-5-4 17:26 编辑

一日 sxd叫儿子去超市打酱油 结账时候拿到一张抽奖卷 到柜台抽奖

柜台前的广告是这么写的:

- 50%拿到 餐巾纸 塑料袋 橡皮筋 中的随机一样

- 12%拿到 糖果 饼干 中的随机一样

- 5%拿到 优惠卷

- 1%拿到 猫粮

- 剩下就是谢谢惠顾了

现需要用au3 来模拟出这个抽奖箱 算法以执行10W次最后统计出来的结果准确度来衡量
(检验方法 算出10W次的结果->统计各类各项奖品在总抽奖次数里的比)

要求:
1.物品列表是可以修改的
2.单次执行时间控制在200ms以内
3.越短越好...!

初级题了...我蛋疼我自重...其实我写的代码太多...想看看有没有更加短的...

200ms的含义:生成一次结果所花费时间...


引起公愤了啊......下面是我自己的...
#include <Array.au3>

$data = StringSplit(StringReplace(FileRead("list.txt"), @CR, ""), @LF, 2)
Dim $list
For $i = 0 To UBound($data)-1
        $spilt = StringSplit($data[$i], ",", 2)
        $flag = False
        For $n = 0 To UBound($list)-1
                If $list[$n] == Int($spilt) Then
                        $flag = True
                        ExitLoop
                EndIf
        Next
        If $flag Then
                $list[$n] = $list[$n] & "," & $spilt
        Else
                ReDim $list[$n+1]
                $list[$n] = Int($spilt)
                $list[$n] = $spilt
        EndIf
Next

_ArrayDisplay($list)

$time = TimerInit()
$r = luckyBox($list)
MsgBox(0, TimerDiff($time), $r)

;~ For $i = 0 To 100000
;~         FileWriteLine("test",luckyBox($list))
;~ Next

;$list
Func luckyBox(ByRef $list)
        $rate = Floor(Random(0, 99999, 1)/1000)
        $weighting = 0
        While 1
                For $i = 1 To UBound($list)-1
                        If ($rate+$weighting) == $list[$i] Then
                                Return $list[$i]
                        EndIf
                Next
                $weighting += 1
        WEnd
EndFunc
list.txt
12,糖果
50,餐巾纸
50,塑料袋
50,橡皮筋
12,饼干
5,优惠卷
1,猫粮
100,谢谢惠顾
测试下来 基本在比例上把(有浮动是很正常的 像p版说的情况是允许少量出现的)... 测试10w次是为了看值的稳定性...
单次平均0.40ms左右...

lchl0588 发表于 2010-5-1 22:16:32

只来帮项!!!!!$a=6.3;随机值能不能在这里控制呢?
For $b=1 To 10 Step $a
MsgBox(0,"",$b)
Next不知道用这个方法能行通不? 这里只是一个例子,语句还有很多的变通哦

afan 发表于 2010-5-2 10:01:22

LZ有没有例子?
个人想法,先按比例生成含有10w个元素的数组,再随机不重复的读取这10W个元素

auto 发表于 2010-5-2 10:19:17

- 50%拿到 餐巾纸 塑料袋 橡皮筋 中的随机一样

- 12%拿到 糖果 饼干 中的随机一样

- 5%拿到 优惠卷

- 1%拿到 猫粮

- 剩下就是谢谢惠顾了

按这个百分比随机存取就可以了

3mile 发表于 2010-5-2 15:28:27

来个笨办法,只是统计没中奖的次数。Local $number
Local $a, $d = "优惠卷", $e = "猫粮"
Local $b = ["餐巾纸", "塑料袋", "橡皮筋"]
Local $c = ["糖果", "饼干"]
;Local
For $i = 1 To 100000
        $a = Random(1, 100)
        If $a < 50 Then ; Returns a value between 0 and 1.
                $msg = $b
                If $a < 12 Then
                        $msg = $c
                        If $a < 5 Then
                                $msgbox = $d
                                If $a < 1 Then
                                        $msg = $e
                                EndIf
                        EndIf
                EndIf
        Else
                $msg = "谢谢惠顾"
                $number += 1
        EndIf
Next
MsgBox(0, 0, "谢谢惠顾次数" & $number)

rence 发表于 2010-5-3 03:02:11

呵呵,学习了

3mile 发表于 2010-5-3 16:49:02

想到蛋疼,只计算了1万次笨方法。请大家指教#include <array.au3>
Local $arr, $arr3
Local $a, $bb = 0, $d = "优惠卷", $e = "猫粮"
Local $b = ["餐巾纸", "塑料袋", "橡皮筋"]
Local $c = ["糖果", "饼干"]
$begin = TimerInit()

For $m = 0 To 99;这里定义计算次数/100,只计算100次得到 1万次抽奖的数组
        Dim $arr2
        For $n = 0 To 99
                $arr2[$n] = $n
        Next

        For $i = 0 To 99
                $rannumber = UBound($arr2) - 1
                $ran = Random(0, $rannumber, 1)
                $arr[$i] = $arr2[$ran]
                Select
                        Case $arr[$i] <= 49
                                $arr[$i] = $b
                        Case $arr[$i] <= 61 And $arr[$i] > 49
                                $arr[$i] = $c
                        Case $arr[$i] <= 66 And $arr[$i] > 61
                                $arr[$i] = $d
                        Case $arr[$i] = 67
                                $arr[$i] = "猫粮"
                        Case $arr[$i] > 67
                                $arr[$i] = "未中奖"
                EndSelect
                _ArrayDelete($arr2, $ran)

        Next

        _ArrayConcatenate($arr3, $arr)
Next
;_ArraySort($arr3)
_ArrayDelete($arr3,0)
$dif = TimerDiff($begin)
_ArrayDisplay($arr3,$dif)

3mile 发表于 2010-5-3 17:20:55


运行10W次的效率实在是太肉了

afan 发表于 2010-5-3 17:36:54

3mile 很热心的说,倒是LZ…

水木子 发表于 2010-5-3 17:49:21

3mile 很热心的说,倒是LZ…
afan 发表于 2010-5-3 17:36 http://www.autoitx.com/images/common/back.gif
是啊!撂个问题在这里也不来过问。
前辈最近很忙吧?忙什么呢?

afan 发表于 2010-5-3 18:00:35

是啊!撂个问题在这里也不来过问。
前辈最近很忙吧?忙什么呢?
水木子 发表于 2010-5-3 17:49 http://www.autoitx.com/images/common/back.gif

忙着睡大觉,天太热,不敢出门,呵呵~

运行10W次的效率实在是太肉了
3mile 发表于 2010-5-3 17:20 http://www.autoitx.com/images/common/back.gif

我想LZ的运行10W次仅是为了检验结果,而实际应用应该只是单次的抽奖,那样应该可以是很快的~ 所以我也在3#提出先按比例生成10W奖池(就不存在再验证了),再每次随机不重复读取奖池的元素

pusofalse 发表于 2010-5-3 18:58:24

本帖最后由 pusofalse 于 2010-5-3 20:18 编辑

10万次和100次有何区别?——貌似这是涉及到统计学的问题。 - -||

先生成一个100个元素的1维数组。
前50赋值为1,表示餐巾纸;
再12赋值为2,表示糖果;
其次的5赋值为3,为优惠券;
再1赋值为4,为猫粮;
余下的元素全部赋值为5,表示未中奖;

循环100次,取一个介于0-99之间的随机数,作为数组的索引序号,获取数组中该元素的值,并记录获取该值的次数,循环完毕,最后对比1/2/3/4/5各自的获取次数。#include <Array.au3>

$iTimer = TimerInit()

Local $aVar, $aOutput

_AssignVar(0, 499, "餐巾纸")
_AssignVar(500, 619, "糖果")
_AssignVar(620, 669, "优惠券")
_AssignVar(670, 679, "猫粮")

For $i = 0 To 999
        $aOutput[$i] = $aVar
Next
_Arraydisplay($aOutput, TimerDiff($iTimer))

Func _AssignVar($iFrom, $iStop, $sVar)
        For $i = $iFrom To $iStop
                $aVar[$i] = $sVar
        Next
EndFunc        ;==>_AssignVar
此题可看作编程解生活中的应用题,在想是否应该打乱数组的顺序,更加接近于生活中人的逻辑。
记得很小的时候去抽奖,抽了10次,结果连续10次都中了,用1块钱买来了10块钱的东西,原因在于所有的奖品分布都集中在了一点,只是凭感觉依次从左至右连续抽了个遍。现在想想上面的代码可能会重现那次的情形。

3mile 发表于 2010-5-3 20:06:37

10万次和100次有何区别?

先生成一个100个元素的1维数组。
前50赋值为1,表示餐巾纸;
再12赋值为2,表 ...
pusofalse 发表于 2010-5-3 18:58 http://www.autoitx.com/images/common/back.gif

呵呵,学习了。
我的想法和P大有些雷同。但应该P大的效率更高吧

auto 发表于 2010-5-3 20:56:02

Dim $arr
$arr = "餐巾纸 塑料袋 橡皮筋 中的随机一样"
$arr = "糖果 饼干 中的随机一样"
$arr = "优惠卷"
$arr = "猫粮"
$arr = "谢谢惠顾了"
$arr = 0
$arr = 0
$arr = 0
$arr = 0
$arr = 0
$begin = TimerInit()
For $i=1 To 100000
        $t = Random(1,100)
        If $t < 51 Then
                $arr += 1
        ElseIf $t < 63 Then
                $arr += 1       
        ElseIf $t < 68 Then
                $arr += 1       
        ElseIf $t< 69 Then
                $arr += 1       
        Else
                $arr += 1       
        EndIf               
Next
$dif = TimerDiff($begin)
MsgBox(0,"时间差",$dif)
$arr = Round ($arr/1000)
$arr = Round ($arr/1000)
$arr = Round ($arr/1000)
$arr = Round ($arr/1000)
$arr = Round ($arr/1000)
_ArrayDisplay($arr, "各类各项奖品在总抽奖次数里的比")
超200ms

C.L 发表于 2010-5-3 20:58:55

本帖最后由 C.L 于 2010-5-3 21:15 编辑

现需要用au3 来模拟出这个抽奖箱 算法以执行10W次最后统计出来的结果准确度来衡量
(检验方法 算出10W次的结果->统计各类各项奖品在总抽奖次数里的比)


LZ好象是要统计中奖的比率,我也来做个练习,10万次超200MS,修改了下,耗时少了点,但还是离200MS有点远~~
$t = TimerInit()

Dim $zhi=0,$tang=0,$juan=0,$liang=0
For $i=0 To 100000
        $s = Random (1,100,1)
        Switch $s
                Case $s<51
                        $zhi +=1
                Case $s>=51 And $s<63
                        $tang += 1
                Case $s>=63 And $s < 68
                        $juan += 1
                Case $s = 68
                        $liang += 1
        EndSwitch
Next

MsgBox (0,TimerDiff ($t),"餐巾纸中了"&$zhi&"次,中奖比率为:"&$zhi/1000&@CRLF& _
                "糖果中了"&$tang&"次,中奖比率为:"&$tang/1000&@CRLF& _
                "优惠券"&$juan&"次,中奖比率为:"&$juan/1000&@CRLF& _
                "猫粮"&$liang&"次,中奖比率为:"&$liang/1000&@CRLF)
页: [1] 2
查看完整版本: 关于依照表取得随机值的问题