算法题——投篮比赛获胜的概率

<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 IntegerByVal ParamArray P() As DoubleAs 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楼   2011-03-22 14:11 |  蒋伟   
马尔可夫链。呵呵
  
#2楼   2011-03-22 15:04 |  szyicol   
貌似算法有些问题!!!
  
#3楼   2011-03-22 17:11 |  六芒星   
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%。
  
#4楼   2011-03-22 21:15 |  我不容易   
楼上算法有漏洞,如果A投中,则加1分,否则并不会减去一分,而是要看B的投篮情况,只有当B成功投中的时候,才会减去一分。在两个人一轮的投篮中,加一分的概率是0.7,减一分的概率是(1-0.7)*0.3=0.09,剩下0.21的概率分数保持不变。
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
=  0.7 ;
=  0.3 ;
upper  =  11 ;
lower  =  0 ;
counter  =  0 ;
for  =  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获胜的次数,与楼主分析一致。
  
#5楼   2011-03-23 09:59 |  六芒星   
@我不容易
抱歉,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 ;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值