Bad Luck Island
如果把问题看作简单抽球,算出来的概率方程会把 $f( i , j , k )$ 消掉。。。
并不知道是为什么,这题好像要把抽到相同种类的球的概率去掉才能正常计算。
定义 $f ( i , j , k )$ 表示最后剩下 $i$ 个石头,$j$ 个剪刀,$k$ 个布的概率。
显然 $f ( r , s , p ) = 1 $,$i,j,k$ 中任意数目大于其对应上限的概率都是 $0$。
然后直接转移就好了:
$$ \begin{aligned} f ( i , j , k ) = & \dfrac { 2 ( i + 1 ) k } { t + 2 j + 2 k } f ( i + 1 , j , k ) + \\ & \dfrac{ 2 ( j + 1 ) i } { t + 2 i + 2 k } f ( i , j + 1 , k ) + \\ & \dfrac { 2 ( k + 1 ) j } { t + 2 i + 2 j } f ( i , j , k + 1 ) \end{aligned} $$
这里直接记忆化就行了,最后把单个物种能存活的概率累加起来就是答案。
时间复杂度 $ O( n ^ 3 ) $。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream> #include <cstdio> #define ll long long #define ld long double using namespace std;namespace Ehnaev{ inline ll read () { ll ret=0 ,f=1 ;char ch=getchar (); while (ch<48 ||ch>57 ) {if (ch==45 ) f=-f;ch=getchar ();} while (ch>=48 &&ch<=57 ) {ret=(ret<<3 )+(ret<<1 )+ch-48 ;ch=getchar ();} return ret*f; } inline void write (ll x) { static char buf[22 ];static ll len=-1 ; if (x>=0 ) {do {buf[++len]=x%10 +48 ;x/=10 ;}while (x);} else {putchar (45 );do {buf[++len]=-(x%10 )+48 ;x/=10 ;}while (x);} while (len>=0 ) putchar (buf[len--]); } }using Ehnaev::read;using Ehnaev::write; const ll N=1e2 ;ll r,s,p; ld ansr,anss,ansp; ld f[N+5 ][N+5 ][N+5 ]; bool vis[N+5 ][N+5 ][N+5 ];inline ld DP (ll i,ll j,ll k) { if (i>r||j>s||k>p) return 0 ; if (vis[i][j][k]) return f[i][j][k];vis[i][j][k]=1 ; ll t=2 *(i*j+j*k+i*k);ld res=0 ; if (t+2 *(j+k)>0 ) res+=(2 *i*k+2 *k)/(ld)(t+2 *(j+k))*DP (i+1 ,j,k); if (t+2 *(i+k)>0 ) res+=(2 *i*j+2 *i)/(ld)(t+2 *(i+k))*DP (i,j+1 ,k); if (t+2 *(i+j)>0 ) res+=(2 *k*j+2 *j)/(ld)(t+2 *(i+j))*DP (i,j,k+1 ); return f[i][j][k]=res; } int main () { r=read ();s=read ();p=read (); f[r][s][p]=1 ;vis[r][s][p]=1 ; for (ll i=1 ;i<=r;i++) {ansr+=DP (i,0 ,0 );} for (ll i=1 ;i<=s;i++) {anss+=DP (0 ,i,0 );} for (ll i=1 ;i<=p;i++) {ansp+=DP (0 ,0 ,i);} printf ("%.12Lf %.12Lf %.12Lf" ,ansr,anss,ansp); return 0 ; }