标签:
一道概率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