掷骰子 概率 动态规划

掷骰子

题目描述

玩家A和B正在玩骰子游戏。

A骰子有6个面,第i个面的点数是sideA[i]。

B骰子有6个面,第i个面的点数是sideB[i]。

玩家A总共掷X次A骰子,每次掷骰子得到的面都是1/6的概率。

玩家B总共掷Y次B骰子,每次掷骰子得到的面都是1/6的概率。

玩家最终的总得分就是每次掷骰子得到的点数的总和。

计算玩家A赢得游戏的概率,即玩家A总得分高于玩家B的总得分的概率。

输入格式

第一行,一个整数G,表示有G组测试数据。 1 <= G <= 10

每组测试数据格式:

第一行,两个整数,X 和 Y。1 <= X,Y <= 200。

第二行,6个整数,第i个整数是sideA[i]。 1 <= sideA[i] <= 100。

扫描二维码关注公众号,回复: 11992531 查看本文章

第三行,6个整数,第i个整数是sideB[i]。 1 <= sideB[i] <= 100。

输出格式

共G行,共G行,每行一个实数,误差不超过0.0001。

输入样例

10
1 1
1 2 3 4 5 6 
1 2 3 4 5 6 
200 200
1 3 8 18 45 100 
1 4 10 21 53 100 
2 3
1 1 1 2 2 2 
1 1 1 1 1 1 
200 200
6 5 4 3 2 1 
3 4 6 5 1 2 
100 199
1 1 1 1 1 2 
1 1 1 1 1 1 
1 1
1 2 1 2 1 2 
2 1 2 1 2 1 
200 80
1 3 8 18 45 100 
1 4 10 21 53 100 
100 100
1 3 5 10 15 20 
9 9 9 9 9 9 
100 100
7 8 9 9 10 11 
1 3 5 10 15 20 
10 1
1 2 3 4 5 6 
59 70 80 90 95 100

输出样例

0.41666666666666663
0.25240407058279035
0.25
0.49416239842107595
1.5306467074865068E-78
0.25
0.9999999976160046
0.4943375131579816
0.49968090996086173
2.7563619479867007E-9

解题思路

题目大意:A掷A骰子X次,B掷B骰子Y次,求A掷出的数值总和比B的高的概率。

我们可以求出A掷完X次骰子后,可能得到的分数的概率,再求出B掷完Y次骰子后可能得分的概率,最后求出A分数高于B分数的概率。

基于以上思路,我们可以用动态规划求解A掷完X次骰子后,可能得到的分数的概率。


f [ i ] [ j ] f[i][j] f[i][j]表示A掷完了 i i i次,得到 j j j分的概率,我们可以推出以下式子:
f [ i ] [ j ] = ∑ 1 ≤ k ≤ 6 f [ i − 1 ] [ j − s i d e A [ k ] ] × 1 6 f[i][j]=\sum_{1\leq k \leq 6}f[i-1][j-sideA[k]]\times\frac{1}{6} f[i][j]=1k6f[i1][jsideA[k]]×61

掷完了 i i i次,得到 j j j分,那么可能在掷第 i i i次之前,已经得到了 j − s i d e A [ k ] j-sideA[k] jsideA[k]分,然后这一次掷出 s i d e A [ k ] sideA[k] sideA[k]的概率是 1 6 \frac{1}{6} 61,因为一个骰子有六个面,会掷出六种情况,所以将这些情况发生的概率求和即为当前情况发生的概率。


同理,求出B掷完了 i i i次,得到 j j j分所有情况的概率。

接着,我们就可以求A分数高于B分数的概率了。

我们只需枚举A可能得到的每一个分数 f A [ X ] [ j ] fA[X][j] fA[X][j]的概率,然后枚举B可能得到的每一个比A目前得分小的分数 f B [ Y ] [ i ] , i ≤ j fB[Y][i],i\leq j fB[Y][i],ij的概率,将这两种情况的概率相乘且将其余情况做相同处理然后求和即为本题答案。

代码(本做法超时,望大佬们帮忙优化)

#include<iostream>
#include<fstream>
#include<cstdio>
#include<iomanip>

using namespace std;
int G,X,Y,a[105],b[105],maxa,maxb;
double pa[205][20015],pb[205][20015],ans,tempa,tempb,pro;
int main()
{
    
    
	freopen("2801.in","r",stdin);
	freopen("2801.out","w",stdout);
	pro=(1.00/6.00);
     scanf("%d",&G);
	 for(int gr=1;gr<=G;gr++)
	 {
    
    
		 scanf("%d%d",&X,&Y);
		 maxa=maxb=0;
		 for(int i=1;i<=6;i++)
	     {
    
    
	    	scanf("%d",&a[i]);
			maxa=max(maxa,a[i]);
		 }
		 for(int i=1;i<=6;i++)
		 {
    
    
			scanf("%d",&b[i]);
			maxb=max(maxb,b[i]);
		 }
		 maxa=maxa*X;
		 maxb=maxb*Y;
		 for(int i=0;i<=max(X,Y);i++)
			for(int j=0;j<=max(maxa,maxb);j++)
				pa[i][j]=pb[i][j]=0.00;
		 ans=0.00;
		 pa[0][0]=pb[0][0]=1.00;
		 for(int i=1;i<=X;i++)
			 for(int j=1;j<=maxa;j++)
				 pa[i][j]=double(pa[i-1][j-a[1]]+pa[i-1][j-a[2]]+pa[i-1][j-a[3]]+pa[i-1][j-a[4]]+pa[i-1][j-a[5]]+pa[i-1][j-a[6]])*pro;
		 
		 for(int i=1;i<=Y;i++)
			 for(int j=1;j<=maxb;j++)
				 pb[i][j]=double(pb[i-1][j-b[1]]+pb[i-1][j-b[2]]+pb[i-1][j-b[3]]+pb[i-1][j-b[4]]+pb[i-1][j-b[5]]+pb[i-1][j-b[6]])*pro;
		 
		 for(int i=1;i<=maxa;i++)
			 for(int j=1;j<i;j++)
				 ans+=pa[X][i]*pb[Y][j];

		 printf("%.6lf\n",ans);
	 }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/bell041030/article/details/89039982