Island of Survival LightOJ - 1265
一个岛上有 t t t 个老虎和 d d d 鹿,还有一个人,每次从中选出来两种动物(包括人),进行操作:
(1)人 和 老虎:老虎吃人
(2)老虎 和 鹿:老虎吃鹿
(3)鹿 和 鹿:啥都不发生
(4)人 和 鹿:人可以选择吃或不吃鹿
(5)老虎 和 老虎:两败俱伤,都死掉
当老虎都死掉的时候人获得胜利,问人的获胜概率是多大(遇见鹿时通过选择来最大化获胜概率)?
首先,老虎必须是偶数只,才有可能都死掉,所以 t t t 为奇数时获胜概率为 0 0 0;其次,每次人遇见鹿时选择不杀,这样有更大的概率给老虎选到鹿。
然后用 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示还有 i i i 只老虎, j j j 只鹿时人的获胜概率, d p [ 0 ] [ j ] = 1 dp[0][j]=1 dp[0][j]=1,则:
d p [ i ] [ j ] = C i 2 C i + j + 1 2 d p [ i − 2 ] [ j ] + C i 1 C j 1 C i + j + 1 2 d p [ i ] [ j − 1 ] + C j 1 + C j 2 C i + j + 1 2 d p [ i ] [ j ] d p [ i ] [ j ] = i ( i − 1 ) / 2 ( i + j + 1 ) ( i + j ) / 2 − j − j ( j − 1 ) / 2 d p [ i − 2 ] [ j ] + i j ( i + j + 1 ) ( i + j ) / 2 − j − j ( j − 1 ) / 2 d p [ i ] [ j − 1 ] d p [ i ] [ j ] = i ( i − 1 ) ( i + j + 1 ) ( i + j ) − j − j 2 d p [ i − 2 ] [ j ] + 2 i j ( i + j + 1 ) ( i + j ) − j − j 2 d p [ i ] [ j − 1 ] \begin{aligned} dp[i][j]&=\frac{C_i^2}{C_{i+j+1}^2}dp[i-2][j]+\frac{C_i^1C_j^1}{C_{i+j+1}^2}dp[i][j-1]+\frac{C_j^1+C_j^2}{C_{i+j+1}^2}dp[i][j]\\ dp[i][j]&=\frac{i(i-1)/2}{(i+j+1)(i+j)/2-j-j(j-1)/2}dp[i-2][j]\\ &+\frac{ij}{(i+j+1)(i+j)/2-j-j(j-1)/2}dp[i][j-1]\\ dp[i][j]&=\frac{i(i-1)}{(i+j+1)(i+j)-j-j^2}dp[i-2][j]\\ &+\frac{2ij}{(i+j+1)(i+j)-j-j^2}dp[i][j-1]\\ \end{aligned} dp[i][j]dp[i][j]dp[i][j]=Ci+j+12Ci2dp[i−2][j]+Ci+j+12Ci1Cj1dp[i][j−1]+Ci+j+12Cj1+Cj2dp[i][j]=(i+j+1)(i+j)/2−j−j(j−1)/2i(i−1)/2dp[i−2][j]+(i+j+1)(i+j)/2−j−j(j−1)/2ijdp[i][j−1]=(i+j+1)(i+j)−j−j2i(i−1)dp[i−2][j]+(i+j+1)(i+j)−j−j22ijdp[i][j−1]
代码如下:
#include<iostream>
#include<cstdio>
//#define WINE
#define MAXN 1005
using namespace std;
int T,iCase,t,d,sum;
double dp[MAXN][MAXN],res;
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&t,&d);
if(t%2!=0){
printf("Case %d: 0\n",++iCase);
continue;
}
for(int i=0;i<=t;i+=2)
for(int j=0;j<=d;j++){
if(i==0){
dp[i][j]=1;
continue;
}
sum=(i+j+1)*(i+j)-j-j*j;
dp[i][j]=i*(i-1)*1.0/sum*dp[i-2][j];
if(j!=0)dp[i][j]+=2.0*i*j/sum*dp[i][j-1];
}
printf("Case %d: %.10lf\n",++iCase,dp[t][d]);
}
return 0-1;
}
还有一种解法是,输赢只和老虎数量有关,设 d p [ i ] dp[i] dp[i] 为有 i i i 只老虎时,人获胜的概率,则:
d p [ i ] = C i 2 C i + 1 2 d p [ i − 2 ] d p [ i ] = i − 1 i + 1 d p [ i − 2 ] \begin{aligned} dp[i]&=\frac{C_i^2}{C_{i+1}^2}dp[i-2]\\ dp[i]&=\frac{i-1}{i+1}dp[i-2] \end{aligned} dp[i]dp[i]=Ci+12Ci2dp[i−2]=i+1i−1dp[i−2]
代码如下:
#include<iostream>
#include<cstdio>
//#define WINE
#define MAXN 1005
using namespace std;
int T,iCase,t,d;
double dp[MAXN];
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&t,&d);
if(t%2!=0){
printf("Case %d: 0\n",++iCase);
continue;
}
dp[0]=1;
for(int i=2;i<=t;i+=2)
dp[i]=1.0*(i-1)/(i+1)*dp[i-2];
printf("Case %d: %.8lf\n",++iCase,dp[t]);
}
return 0;
}
(没写时间是因为用时 0ms…)