LightOJ 1265 Island of Survival 概率DP

Island of Survival LightOJ - 1265

一个岛上有 tt 个老虎和 dd 鹿,还有一个人,每次从中选出来两种动物(包括人),进行操作:

(1)人 和 老虎:老虎吃人
(2)老虎 和 鹿:老虎吃鹿
(3)鹿 和 鹿:啥都不发生
(4)人 和 鹿:人可以选择吃或不吃鹿
(5)老虎 和 老虎:两败俱伤,都死掉

当老虎都死掉的时候人获得胜利,问人的获胜概率是多大(遇见鹿时通过选择来最大化获胜概率)?

首先,老虎必须是偶数只,才有可能都死掉,所以 tt 为奇数时获胜概率为 00;其次,每次人遇见鹿时选择不杀,这样有更大的概率给老虎选到鹿。

然后用 dp[i][j]dp[i][j] 表示还有 ii 只老虎,jj 只鹿时人的获胜概率,dp[0][j]=1dp[0][j]=1,则:

dp[i][j]=Ci2Ci+j+12dp[i2][j]+Ci1Cj1Ci+j+12dp[i][j1]+Cj1+Cj2Ci+j+12dp[i][j]dp[i][j]=i(i1)/2(i+j+1)(i+j)/2jj(j1)/2dp[i2][j]+ij(i+j+1)(i+j)/2jj(j1)/2dp[i][j1]dp[i][j]=i(i1)(i+j+1)(i+j)jj2dp[i2][j]+2ij(i+j+1)(i+j)jj2dp[i][j1] \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}

代码如下:

#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;
}

在这里插入图片描述

还有一种解法是,输赢只和老虎数量有关,设 dp[i]dp[i] 为有 ii 只老虎时,人获胜的概率,则:

dp[i]=Ci2Ci+12dp[i2]dp[i]=i1i+1dp[i2] \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}

代码如下:

#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…)

posted @ 2020-03-25 10:27  winechord  阅读(79)  评论(0编辑  收藏  举报