CF - 540D 概率dp

题意:

有一个岛上有剪刀,石头,布各x,y,z个,每天都会有两个人相遇,如果是相同属性的两个人,则不会发生任何事,如果是不同属性的两个人,会有一个人被消灭。消灭的规则就是
1.剪刀 消灭 布
2.布   消灭 石头
3.石头 消灭 剪刀
假设经过无限长的时间,最后岛上只剩下一种人的概率分别是多少?


思路:

经典的概率dp,x,y,z都不大,很容易想到状态的设计dp[i][j][k]表示当前岛上剪刀,石头,布分别还剩i,j,k的概率。初始化显然是dp[x][y][z] = 1,最后要求的结果就是对于每一种来说就是其他两种为0时的所有概率的和。

关键在于状态转移方程的确定。其实对于概率dp,状态转移方程的设计都是由全概率公式推导而来的。对于当前的某个状态dp[i][j][k],它可以由四个状态转移过来,dp[i+1][j][k], dp[i][j+1][k], dp[i][j][k+1] 以及它本身。
根据全概率公式就可以列出状态转移方程:
dp[i][j][k] = p1*dp[i+1][j][k] + p2*dp[i][j+1][k] + p3*dp[i][j][k+1] + (1-p1-p2-p3)*dp[i][j][k];
移项变化以下可以得到以下式子:
dp[i][j][k] = (p1*dp[i+1][j][k] + p2*dp[i][j+1][k] + p3*dp[i][j][k+1]) / (p1+p2+p3);
其中p1,p2,p3都可以根据i,j,k求出,这样三重循环倒序dp以下即可。


代码:

#include <bits/stdc++.h>
using namespace std;

double dp[110][110][110];
int main() {
    //freopen("in", "r", stdin);
    int x, y, z;
    scanf("%d%d%d",&x, &y, &z);
    dp[x][y][z] = 1;
    for(int i = x; i >= 0; i--) {
        for(int j= y; j >= 0; j--) {
            for(int k = z; k >= 0; k--)  {
                //printf("%d %d %d %lf\n ",i,j,k,dp[i][j][k]);
                if(i + j == 0 || i + k == 0 || j + k == 0) continue;
                double tem = 0;
                if(k != 0) tem += 1.0 * j * k / (i + j + k) / (i + j + k - 1);
                if(j != 0) tem += 1.0 * j * i / (i + j + k) / (i + j + k - 1);
                if(i != 0) tem += 1.0 * i * k / (i + j + k) / (i + j + k - 1);
                if(k != 0)
                    dp[i][j][k - 1] += dp[i][j][k] * j * k / (i + j + k) / (i + j + k - 1) / tem;
                if(j != 0)
                    dp[i][j - 1][k] += dp[i][j][k] * j * i / (i + j + k) / (i + j + k - 1) / tem;
                if(i != 0)
                    dp[i - 1][j][k] += dp[i][j][k] * i * k / (i + j + k) / (i + j + k - 1) / tem;
            }
        }
    }
    double ax = 0, ay = 0, az = 0;
    for(int i = 1; i <= y; i++) ay += dp[0][i][0];
    for(int i = 1; i <= x; i++) ax += dp[i][0][0];
    for(int i = 1; i <= z; i++) az += dp[0][0][i];
    printf("%.9lf %.9lf %.9lf\n", ax, ay, az);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值