牛牛与牛妹的游戏

链接:https://ac.nowcoder.com/acm/problem/21626

题目:

牛牛 和 牛妹 正在玩一个游戏

牛牛扔了a个b面的骰子

牛妹扔了c个d面的骰子

对于一个x面的骰子,每个面依次会写有1到x的数

一个玩家的得分就是每个骰子朝上的面的数字的总和,一个玩家能赢另一个玩家当且仅当得分严格大于另一个玩家,给你a,b,c,d,如果牛牛不可能赢,输出-1

否则假设你知道了牛牛赢了,但是不知道牛牛和牛妹的具体分数,返回牛牛的期望得分

输入一行,包含4个整数a,b,c,d (1 ≤ a,b,c,d ≤ 50)
输出一个浮点数,误差在1e-3以内
输入
1 2 1 5
输出
2.0

示例 2
输入
3 1 1 3
输出
3.0

示例3
输入
1 5 1 1
输出
3.4999999999999996

示例4
输入
2 6 50 30
输出
-1.0

示例5
输入
50 11 50 50 
输出
369.8865999182022

思路:题目意思是牛牛能赢的情况下的得分期望,所以我们只需要算出牛牛能赢的所有情况的总数,再算出牛牛能赢的每一种情况下牛牛能得的分,计算其总和,两者相除即可;dp[i][j]表示掷了i个骰子,得分为j的情况的有多少种.

递推方程:
dp[i][j]+=dp[i-1][j-k] (j>=k,k代表第i个骰子的点数)
代码:
//牛牛与牛妹的游戏

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn=55;
double dp1[maxn][2600], dp2[maxn][2600];
double add[2600];    //add[j]牛妹的得分小于等于j的情况有多少种
int main()
{
	int a,b,c,d;
	double ans=0;
	scanf("%d%d%d%d", &a, &b, &c, &d);
//	memset(dp,0,sizeof(dp));
	dp1[0][0]=1;
	dp2[0][0]=1;
	if(a*b<=c) printf("-1.0\n");
	else
	{
		for(int i=1; i<=a; i++)
		{
			for(int j=i; j<=b*i; j++)
			{
				for(int k=1; k<=b; k++)
				{
			     	 if(j>=k) dp1[i][j]+=dp1[i-1][j-k];  //牛牛第i回合得j分的可能情况数
				}
			}
		}

		for(int i=1; i<=c; i++)
		{
			for(int j=i; j<=d*i; j++)
			{
				for(int k=1; k<=d; k++)
				{
			     	 if(j>=k) dp2[i][j]+=dp2[i-1][j-k];  //牛妹第i回合得j分的可能情况数
				}
			}
		}
		for(int i=c; i<=c*d; i++) 
		{
			add[i]+=add[i-1]+dp2[c][i];   
		}
		double result1, result2=0;
		for(int i=c+1; i<=a*b; i++) 
		{
			result2+=dp1[a][i]*(add[i-1] ? add[i-1] : add[c*d]);   //计算分母
		}
		for(int i=c; i<=c*d; i++) 
		{
			for(int j=i+1; j<=a*b; j++)
			{
				result1+=dp1[a][j]*j*dp2[c][i];  //分子
			}
		}
	printf("%lf\n", result1/result2);
	}
	return 0;
}

你可能感兴趣的:(概率dp)