链接: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;
}