题目链接:
题目大意:
给出w只白老鼠,b只黑老鼠,公主和龙轮流取老鼠,公主先手,龙取老鼠时会吓跑一只老鼠,先取出白老鼠的人赢,如果没人取到白老鼠,那么龙赢。问公主赢的概率。
题目分析:
- 首先定义状态dp[i][j]表示第i次取老鼠时剩余黑老鼠为j的概率。
- 那么最后结果就是
∑i为奇数∑j=0bdp[i][j]
- 那么怎么转移呢?分两种情况
- i&1 :
dp[i][j]=dp[i−1][j+1]⋅j+1sumi−1
- else:
dp[i][j]=dp[i−1][j+1]⋅(j+1)⋅(sumi−1−j−1)sumi−1⋅sumi−1−1
- i&1 :
- 然后就是注意边界情况了,因为double值在边界情况上会出现很多情况,具体特判见代码
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 1007
using namespace std;
double dp[MAX][MAX];
int w,b,sum;
void calc ( int x )
{
sum = x+x/2;
sum = w+b-sum;
}
int main ( )
{
while ( ~scanf ( "%d%d" , &w , &b ) )
{
if ( w == 0 )
{
puts ("0.0000000000" );
continue;
}
memset ( dp , 0 ,sizeof ( dp ) );
dp[0][b] = 1.0;
for ( int i = 1 ; i <= b; i++ )
{
calc ( i-1 );
for ( int j = 0; j <= b ; j++ )
{
dp[i][j] = 0;
if ( i&1 )
dp[i][j] = dp[i-1][j+1]*((j+1)*1.0/(sum*1.0));
else
{
double x = (j+1)*(j+2)*1.0/(sum*(sum-1)*1.0);
dp[i][j] += dp[i-1][j+2]*x;
x = (j+1)*(sum-1-j)*1.0/(sum*(sum-1)*1.0);
dp[i][j] += dp[i-1][j+1]*x;
}
}
}
double ans = 0;
for ( int i = 0 ; i <= b ; i += 2 )
for ( int j = 0 ; j <= b ; j++ )
{
calc ( i );
if ( sum == 0 || sum < j ) continue;
//cout << dp[i][j] << " " << ans << endl;
ans += dp[i][j]*((sum-j) *1.0/(sum*1.0));
}
printf ( "%.10lf\n" , ans );
}
}