题意:
石头、剪刀、布这3种动物生活在一个荒岛上,石头吃剪刀、剪刀吃布、布吃石头。现已知这3种动物各有r、s、p只,问等到足够的时间过后,这岛上最后剩下的动物是哪一种(不要想着最后的物种会饿死啦~),求每种动物剩下的概率。
分析:
一开始纯搜索--超时,觉着这数据量只是算出每种概率的话应该不会超时,所以可能是记忆化搜索?然后写着写着总感觉哪不对。。然后发现别人直接dp。。对啊,直接dp也可以啊。。于是瞬间写出dp表达式。两种物种相遇的概率是:(x*y)/(x*y+x*z+y*z)。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 1<<30
double dp[110][110][110];
double R, S, P;
int main()
{
int r, s, p;
cin >> r >> s >> p;
dp[r][s][p] = 1.0;
for(int i=r; i>=0; i--)
{
for(int j=s; j>=0; j--)
{
for(int k=p; k>=0; k--)
{
double sum = i*j+i*k+j*k;
if(i && sum) dp[i-1][j][k] += (i*k)/sum*dp[i][j][k];
if(j && sum) dp[i][j-1][k] += (i*j)/sum*dp[i][j][k];
if(k && sum) dp[i][j][k-1] += (j*k)/sum*dp[i][j][k];
}
}
}
for(int i=0; i<=r; i++)
R += dp[i][0][0];
for(int i=0; i<=s; i++)
S += dp[0][i][0];
for(int i=0; i<=p; i++)
P += dp[0][0][i];
printf("%.9f %.9f %.9f\n", R,S,P);
return 0;
}
记忆化搜索:
#include<stdio.h>
double dp[110][110][110];
double dfs(int r, int s, int p)
{
if(dp[r][s][p]) return dp[r][s][p];
if(p == 0) return 1; //当p==0也就是说,当p灭绝,此时最终留下来的是物种r
if(s*r == 0) return 0; //表示物种r或s灭绝的概率为0,因为我已假设就是p物种灭绝
//一直算到有一种物种灭绝,这样就可以直接知道谁存活,是不是满足自己的假设
int sum = r*s+r*p+s*p;
return dp[r][s][p] = 1.0*r*s/sum*dfs(r,s-1,p)+1.0*r*p/sum*dfs(r-1,s,p)+1.0*s*p/sum*dfs(r,s,p-1);
}
int main()
{
int r, s, p;
scanf("%d%d%d", &r,&s,&p);
printf("%.9f %.9f %.9f\n", dfs(r,s,p),dfs(s,p,r),dfs(p,r,s));
//dfs(i,j,k)表示i存活,算到k灭绝为止
return 0;
}