抽彩票

题目描述

PIPI和POPO在玩一个抽彩票的游戏,彩票箱里有n张能中奖的彩票和 m 张不能中奖的彩票。PIPI和POPO轮流抽彩票,抽取彩票采取不放回的抽取方式,PIPI先抽,如果PIPI抽到了能中奖了的彩票,那么PIPI就赢了, 游戏结束。POPO后抽,如果POPO抽到能中奖的彩票,POPO也就赢了,游戏结束。否则的话,POPO就还会从彩票箱里抽一张彩票, 不管这张彩票中了没有,POPO都会拿出来扔掉。如果彩票箱里没有彩票了,那么POPO获胜。请问你PIPI最终的胜率是多少?

输入

输入一行,一个正整数 n 和 m (0<=n,m<=1000)

输出

输出PIPI获胜的概率,结果保留4位小数。

样例输入

2 3

样例输出

0.6000

/*
概率 dp, 这里采用记忆化搜索的写法,dp[i][j]代表彩票箱中有 i 张中奖彩票,j 张不中奖彩票时 PIPI 的胜率。
那么 i等于 0 时,PIPI 胜率为 0。i 不等于 0,并且 j 等于 0 时,PIPI 胜率为 1。这样就定义了递归的边界状态。否则,dp[i][j]
将进行以下 4 种转移:
1) PIPI 抽中的中奖彩票 , 直接赢,获胜概率为 i / (i+j);
2) PIPI 抽中非中奖彩票,POPO 抽中中奖彩票,获胜概率 0;
3) PIPI 抽中非中奖彩票,POPO 抽中非中奖彩票,POPO 再抽,抽中中奖彩票,丢弃,这种情况下 PIPI 的获胜概
率为 j/(i+j) * (j-1)/(i+j-1) * i / (i+j-2) * dp[i-1][j-2];
4) PIPI 抽中非中奖彩票,POPO 抽中非中奖彩票,POPO 再抽,抽中非中奖彩票,丢弃,这种情况下 PIPI 的获胜
概率为 j/(i+j) * (j-1)/(i+j-1) * (j-2) / (i+j-2) * dp[i][j-3];
dp[i][j]为上述 4 种情况的胜率之和。 
*/
#include
using namespace std;
const int N=1005;
double dp[N][N];
double dfs(int n,int m){ ///记忆化搜索 
    if(n==0) return 0; ///边界条件,当n=0时,pipi获胜的概率为 0 
    if(m==0) return 1; ///边界条件,当m=0时,pipi获胜的概率为 1 
    double& ans=dp[n][m];
    if(ans) return ans;///如果ans不为0,直接返回ans的值 
    double all=n+m;
    ans+=n/all; ///ans表示pipi获胜的概率之和 
    if(m>1){
        ans+=m/all*(m-1)/(all-1)*n/(all-2)*dfs(n-1,m-2);
    }
    if(m>2){
        ans+=m/all*(m-1)/(all-1)*(m-2)/(all-2)*dfs(n,m-3);
    }
    return ans;
}
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    printf("%.4f",dfs(n,m));
}

你可能感兴趣的:(oj刷题)