码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Div.301D Bad Luck Island(概率dp+记忆化搜索)

时间:2015-05-02 23:17:07      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:

一道概率dp问题。

题目链接:http://codeforces.com/contest/540/problem/D

题目大意:一个岛上有r个石头,s个剪子,p个布,他们之间随机挑出两个相遇,如果不是相同物种,就会有一个消失,分别求出最后这座岛上只剩下一个物种的概率。

我们用dp[i][j][k]来存储i个石头,j个剪刀,k个布时,某物种的存活概率,共dp三次,算出三个物种分别的概率。

首先,我们需要把对应想求的物种概率初始化,这里以石头为例,那么对于i从1到r,不难理解dp[i][0][0]=1.0。

然后,以如下状态转移方程:

技术分享

其中,dp[i][j][k]可由dp[i][j-1][k],dp[i][j][k-1],dp[i-1][j][k]得到,例如对dp[i][j-1][k]——i个石头、j-1个剪刀和k个布时石头存活的概率,乘以对应的比例i*j;其他三个做法相同。

通过记忆化搜索一次即可得到对应的结果。同理,分别求三次。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MAXN 110
double dp[MAXN][MAXN][MAXN];
bool vis[MAXN][MAXN][MAXN];
int r, s, p;
void init() {
    memset(vis, false, sizeof(vis));
    memset(dp, 0, sizeof(dp));
    vis[0][0][0] = true;
}
void dfs(int i, int j, int k) {
    if(i < 0 || j < 0 || k < 0) return;
    if(vis[i][j][k]) return;
    vis[i][j][k] = true;
    int sum = 0;

    dfs(i, j - 1, k);
    sum += i * j;
    dp[i][j][k] += (double)(i * j) * dp[i][j-1][k];

    dfs(i, j, k - 1);
    sum += j * k;
    dp[i][j][k] += (double)(j * k) * dp[i][j][k-1];

    dfs(i - 1, j, k);
    sum += k * i;
    dp[i][j][k] += (double)(k * i) * dp[i-1][j][k];

    if(sum == 0) return;
    dp[i][j][k] /= (double)sum;
}
int main() {
    scanf("%d%d%d", &r, &s, &p);
    init();
    for(int i = 1; i <= r; i++) dp[i][0][0] = 1.0;
    dfs(r, s, p);
    printf("%.10lf ", dp[r][s][p]);
    init();
    for(int i = 1; i <= s; i++) dp[0][i][0] = 1.0;
    dfs(r, s, p);
    printf("%.10lf ", dp[r][s][p]);
    init();
    for(int i = 1; i <= p; i++) dp[0][0][i] = 1.0;
    dfs(r, s, p);
    printf("%.10lf\n", dp[r][s][p]);
    return 0;
}

  

Codeforces Div.301D Bad Luck Island(概率dp+记忆化搜索)

标签:

原文地址:http://www.cnblogs.com/gaoxiang36999/p/4472590.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!