石头剪刀布
题意:
桌面上有 个石头, 个剪刀和 个布。
每次等概率选择两个(种类)不同的物品进行剪刀石头布,将输掉的物品移出桌面。
求最后桌面上只剩下石头的概率,和只剩下剪刀的概率,和只剩下布的概率。保留八位小数。
解法:
用 表示剩余 个石头, 个剪刀和 个布的概率。则状态转移方程为 其中 其他情况类似。
参考代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int MAXN=1e2+10;
double dp[MAXN][MAXN][MAXN];
int r,s,p;
inline double prob(int a,int b,int c){
return 1.0*a*b/(a*b+b*c+c*a);
}
void calc(int i,int j,int k){
if (i&&k) dp[i-1][j][k]+=dp[i][j][k]*prob(i,k,j);
if (i&&j) dp[i][j-1][k]+=dp[i][j][k]*prob(i,j,k);
if (j&&k) dp[i][j][k-1]+=dp[i][j][k]*prob(j,k,i);
}
void solve(){
for (int x=0;x<r+s+p;x++)
for (int i=0;i<=std::min(x,r);i++)
for (int j=0;j<=std::min(x-i,s);j++)
calc(r-i,s-j,p-(x-i-j));
double rr=0,ss=0,pp=0;
for (int i=1;i<=r;++i)
rr+=dp[i][0][0];
for (int i=1;i<=s;++i)
ss+=dp[0][i][0];
for (int i=1;i<=p;++i)
pp+=dp[0][0][i];
printf("%.8lf %.8lf %.8lf\n",rr,ss,pp);
}
int main(){
// freopen("k.in","r",stdin);
// freopen("k.out","w",stdout);
scanf("%d%d%d",&r,&s,&p);
memset(dp,0,sizeof(dp));
dp[r][s][p]=1;
solve();
}
v and x
题意:
有两个变量 ,初始全为 。每一次操作有 的概率将 自增 ,有 的概率将 自增 。当 时结束操作。问 的期望。保留六位小数。
解法:
当 时,往后只有两种情况:一, 自增,然后继续;二, 自增,结束。则该情况下的期望为
当 时,期望分为两部分,即
此外还有边界条件的处理。因为 的状态转移为 如果直接迭代会没有结果。但是通过人为的运算,就用刚才的那个“无限递归式”,我们得到 则下面只需计算 即可。
参考代码:
#include <cstdio>
#include <cstring>
const int MAXN=1e3+10;
double dp[MAXN][MAXN];
int k,pa,pb;
double p1,p2;
double solve(int v,int x){
if (dp[v][x]) return dp[v][x];
if (v+x>=k) return dp[v][x]=p2*((v+x)/(1-p1)+p1/(1-p1)/(1-p1));
return dp[v][x]=p1*solve(v+1,x)+p2*solve(v,x+v);
}
int main(){
memset(dp,0,sizeof(dp));
scanf("%d%d%d",&k,&pa,&pb);
p1=1.0*pa/(pa+pb);
p2=1.0*pb/(pa+pb);
printf("%.6lf\n",p1*solve(1,0)/(1-p2));
return 0;
}
Collecting Bugs
题意:
某软件有 个子系统,会产生 种bug。某人一天能发现一个bug,不同子系统和种类中发现bug是等可能性的。现发现了 种bug,问每个子系统都发现bug的天数的期望。
解法:
用 表示已找到 种 个子系统的bug后剩余天数的期望,则显然有 ,题中所求为 。对于一个状态 ,当新发现了一个bug时,可能会出现:
- 发现已有分类和已有子系统的bug,概率为
- 发现已有的分类未有子系统的bug,概率为
- 发现未有的分类已有子系统的bug,概率为
- 发现未有分类和未有子系统的bug,概率为
则有
整理得状态转移方程为 dp[i][j]=(i*(s-j)*dp[i][j+1]+(n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(n*s-i*j)
。
由于是POJ的题目,最后需要用%f
输出而不是%lf
。
参考代码:
#include <cstdio>
const int MAXN=1e3+10;
double dp[MAXN][MAXN];
int n,s;
double solve(){
dp[n][s]=0;
for (int i=n;i>=0;i--){
for (int j=s;j>=0;j--){
if (i==n&&j==s) continue;
dp[i][j]=(i*(s-j)*dp[i][j+1]+(n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(n*s-i*j);
}
}
return dp[0][0];
}
int main(){
while(~scanf("%d%d",&n,&s)){
printf("%.4lf\n",solve());
}
return 0;
}