<span style="background-color: rgb(254, 254, 242); font-family: Verdana, Arial, Helvetica, sans-serif;">近日,在和他人闲暇无事的时候,进行篮球投篮比赛。由于本人的投篮命中率比较低,而他的投篮命中率比较高。因此,定了一个规则。采用积分制,初始积分为1分。他投篮,每投中一个球,积分加1分,继续投篮;投不中,换我投篮。我投篮,每投中一个球,积分减1分,继续投篮;投不中,换他投篮。若积分到11分,他获胜;若积分减到0分,我获胜。每局由他先投篮。</span>
在进行若干局的比赛后,各有胜负。提出了一个问题:他获胜的概率是多少?
把问题数字化
A和B两人进行投篮,A的命中率为70%,B的命中率为30%。初始积分为1分,每人投中继续投,投不中换人投。A投中积分加1分,B投中积分减1分。积分为11分时,A获胜;积分为0分时,B获胜。问:A获胜的概率是多少?
想到这个问题的时候,没有丝毫头绪。因此采用计算机模拟的方式来计算概率。
先写了一个函数
Private Function Winner(ByVal Steps As Integer, ByVal ParamArray P() As Double) As Boolean
Dim I As Integer = 1, J As Integer = 0
Do While I > 0 And I < Steps
If mR.NextDouble < P(J) Then
I += (-1) ^ J
Else
J = 1 - J
End If
Loop
Return (I > 0)
End Function
这个函数是模拟一次投篮。如下调用:Winner(11, 0.7, 0.3)。表示A的投篮命中是0.7,B的投篮命中是0.3,积分到11表示A获胜。函数返回True表示A获胜,返回False表示B获胜。
用了一个循环,模拟1000000局,统计A获胜的局数。得到如下结果:816628。
又反复执行了9个1000000局,结果如下:816502、815734、816220、816972、816756、816473、816636、816226、816290。可以看出,A获胜的概率大致为81.65%
如果积分到21分表示A获胜,那么A获胜的概率是多少呢?
还是上面的代码。模拟1000000局,统计A获胜的局数。执行10次。结果如下:
816116、816358、816242、816436、816677、816319、815949、815822、815860、816616
A获胜的概率大致为81.6%。没有想象中的差异那么大。只是略微少了那么一点点。
那么,如果用数学的计算方法,该如何计算呢?
我的代码:
package basketball;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TouLan {
private static int score;
private static boolean isRandom = false;
private static final int[] nums = {0,0,0,1,1,1,1,1,1,1};
private static final List<Integer> numsList = new ArrayList<Integer>();
public static void main(String[] args) {
int times = 100000;
int onetimes = 0;
for(int i = 0 ;i < times ; i ++){
int toulanNum = start();
System.out.println("sc: " + score);
if(toulanNum == 11){
onetimes ++;
//System.out.println("高手胜利");
}
else if(toulanNum == 0){
//System.out.println("低手胜利");
}
else{
System.out.println("其他");
}
}
System.out.println("Pre: " + (onetimes * 100.00 ) / times + "%");
}
public static int start(){
score = 1;
astart();
return score;
}
//====================================
private static Integer tulan(){
if(!isRandom){
Collections.sort(numsList);
isRandom = true;
}
int position = (int)(Math.random() * 10);
//System.out.println("Position:" + position);
return numsList.get(position);
}
private static void astart(){
if(score == 0 || score == 11){
return ;
}
if(tulan() == 1){
score ++;
astart();
}else{
bstart();
}
}
private static void bstart(){
if(score == 0 || score == 11){
return ;
}
if(tulan() == 0){
score --;
bstart();
}else{
astart();
}
}
}
说明,我写的代码比较垃圾,没有原作者的实现方法好,回帖里面有些不错的想法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
private
static
int
calc() {
double
rateA =
0.7
;
double
rateB =
0.3
;
int
score =
1
;
boolean
isA =
true
;
int
cp;
Random r =
new
Random(
new
Date().getTime());
while
(
true
) {
if
(isA) {
cp = (
int
) (
10
* rateA);
}
else
{
cp = (
int
) (
10
* rateB);
}
int
temp = r.nextInt(
10
);
if
(temp < cp) {
if
(isA)
score++;
else
score--;
}
else
{
isA = !isA;
}
if
(score ==
0
) {
return
1
;
}
if
(score ==
11
) {
return
0
;
}
}
}
|
个人算法
取0-9的随机数。A取到0-6算成功,否则换B;B取到0-3算成功,否则换A。
1000000*100的A胜率测试结果大致是46%-47%。
Matlab代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
A
=
0.7
;
B
=
0.3
;
upper
=
11
;
lower
=
0
;
counter
=
0
;
for
i
=
1
:
100000
score
=
1
;
while
score < upper && score > lower
while
rand <
=
A
score
=
score
+
1
;
if
score
=
=
upper
break
;
end
end
if
score
=
=
upper
break
;
end
while
rand <
=
B
score
=
score
-
1
;
if
score
=
=
lower
break
;
end
end
end
if
score
=
=
upper
counter
=
counter
+
1
;
end
end
|
最终counter记录A获胜的次数,与楼主分析一致。
抱歉,Matlab我不懂
我的算法加些注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
if
(isA) {
// A投篮时候
cp = (
int
) (
10
* rateA);
}
else
{
// B投篮时候
cp = (
int
) (
10
* rateB);
}
int
temp = r.nextInt(
10
);
if
(temp < cp) {
// 进篮的情况
// A投进
if
(isA)
score++;
// B投进
else
score--;
}
else
{
// 不进,换人
isA = !isA;
}
if
(score ==
0
) {
return
0
;
}
if
(score ==
11
) {
return
1
;
}
|