题目
5.1 training 1
题意:
网球比赛:
一场比赛由5场轮换发球的sets组成,五局三胜制。
一场set由轮换发球的games组成,至少得6分且领先对方4分获胜。
一场game由同一个人发球的scores组成,至少得4分且领先对方2分获胜。
已知一个人自己发球和对方发球时赢得一个score的概率,且一开始由他先发球,求赢得比赛的概率。
题解:
比赛的时候想来想去,“领先对方X分获胜”的部分都只能想到暴力,DP递推和矩阵快速幂都用过,全T了。刷了一些概率DP后终于会做了,其实不难。
以计算赢得一场set为例,假设先后手赢得一场game的概率为m,y。
设ans为答案,dp[i][j]表示比分为i:j的概率,先用普通DP算出dp[0~i][0~j],则ans=dp[6][0~4]。
对于两人至少得5分的场合,设f[i]表示领先对方i分时要获胜的概率。
那么:
f[-1]=f[0]*y
f[0]=f[1]*m+f[-1]*(1-m)
f[1]=f[2]*y+f[0]*(1-y)
显然f[2]=1,所以可以求得f[i]具体的值,而到达f[0]的概率是dp[5][5],所以ans=ans+f[0]*dp[5][5]。(用f[1]或f[-1]也可以)
//Time:49ms //Memory:0KB //Length:1687B #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <vector> #include <map> #include <queue> #include <set> #define MAXN 100010 #define INF 1000000007 #define MP(x,y) make_pair(x,y) #define FI first #define SE second #define EPS 1e-8 using namespace std; double dp[10][10]; void cal2(double m,double y,int win) { for(int i=0;i<=win;++i) for(int j=0;j<=win;++j) dp[i][j]=0; dp[0][0]=1; // for(int i=1;i<=win;++i) // dp[i][0]+=dp[i-1][0]*(i&1?m:y), // dp[0][i]+=dp[0][i-1]*(i&1?1-m:1-y); for(int i=0;i<=win;++i) for(int j=0;j<=win;++j) { if(i==win&&j<=win-2) continue; if(j==win&&i<=win-2) continue; dp[i+1][j]+=dp[i][j]*((i+j)&1?m:y); dp[i][j+1]+=dp[i][j]*((i+j)&1?1-m:1-y); } return ; } double cal(double m,double y,int tied) { double ans=0,tmp; cal2(m,y,tied+1); for(int i=0;i<tied;++i) ans+=dp[tied+1][i]; tmp=y*(1-y*(1-m))/(1-m-y+2*m*y); tmp*=m/(1-y*(1-m)); ans+=dp[tied][tied]*tmp; return ans; } int main() { //freopen("/home/moor/Code/input","r",stdin); int ncase; double m2,y2,m,y,m3,y3,ans; scanf("%d",&ncase); for(int hh=1;hh<=ncase;++hh) { scanf("%lf%lf",&m,&y); m/=100.0,y/=100.0; m2=cal(m,m,3); y2=cal(y,y,3); m3=cal(m2,y2,5); y3=cal(y2,m2,5); cal2(m3,y3,3); ans=0; for(int i=0;i<=2;++i) ans+=dp[3][i]; printf("Case #%d: %.4f%%\n",hh,ans*100); } return 0; }