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