目录
题目:抓老鼠
题意:一共有w只白鼠b只黑鼠,AB俩人轮流抓鼠,过程是这样的:A先抓一只然后B抓一只然后跑掉一只,抓到白鼠时此人获胜。我们设定两者都没抓到则B获胜,A先抓。问A获胜的概率?
思路:
我们设置:dp[i][j]表示当前里面有i只白鼠j只黑鼠时 A先手的胜率。自然dp[0][i]=0,dp[i][0]=1,dp[i][1]=i/(i+1),我们要求dp[w][b]
dp[i][j]的概率是要么直接当局获胜i/(i+j),要么后局获胜。
dp[i][j]=1.0*i/(i+j)
dp[i][j]+=j/(i+j)*(j-1)/(i+j-1)* i /(i+j-2)*dp[i-1][j-2];//先手抓黑,后手抓黑,跑只白的情况映射到dp[i-1][j-2]
dp[i][j]+=j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3];//先手抓黑,后手抓黑,跑只黑的情况映射到dp[i][j-3]
初始化:其实对于dp[i][1]的结果已经固定了,所以完全可以在双for循环(都是从1开始)的时候进行初始化的。
#include <bits/stdc++.h>
using namespace std;
double dp[1005][1005];//dp[i][j]表示i只白鼠,j只黑鼠时,A先手的胜率
int main(){
int w,b;
cin>>w>>b;
for(int i=1;i<=w;i++) dp[i][0]=1.0,dp[i][1]=1.0*i/(i+1);
for(int i=1;i<=w;i++){
for(int j=2;j<=b;j++){
dp[i][j]=1.0*i/(i+j);//处理当前的获胜概率
dp[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2];
if(j>=3) dp[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3];
}
}
printf("%.9lf",dp[w][b]);
return 0;
}
题目:抽奖概率
有一个抽奖活动:抽一个2元,可能会抽出1,2,3,4元(概率相等)。
问抽n次,亏本的概率是多少(奖金小于本金)?纯赚超过一半本金的概率是多少
(分数时候输出最简分数)
输入:2 输出:3/16
3/16
思路:
直接求概率不太容易。而且还要最简分数,那么就转化乘求方案数就会具体很多。
设置dp[i][j]表示已经抽奖i次且拿到了总额为j的方案数.dp[i][j]+=dp[i-1][j-1,j-2,j-3,j-4]
最后的最简分数可以使用gcd函数完成。
初始化:这种初始化有点多余,第一轮的循环完全就是做样子,可以直接从第二轮开始。
#include <bits/stdc++.h>
using namespace std;
int dp[40][160],n;
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int main(){
cin>>n;
dp[1][1]=dp[1][2]=dp[1][3]=dp[1][4]=1;
for(int i=1;i<=n;i++)
for(int j=i;j<=4*n;j++){
for(int k=1;k<=4;k++)
if(j>k) dp[i][j]+=dp[i-1][j-k];
}
int sum1=0,sum2=0,sum=1;
for(int i=n;i<2*n;i++)
sum1+=dp[n][i];
for(int i=3*n+1;i<=4*n;i++)
sum2+=dp[n][i];
for(int i=1;i<=n;i++)
sum*=4;
int k=gcd(sum1,sum);
cout<<sum1/k<<"/"<<sum/k<<'\n';
k=gcd(sum2,sum);
cout<<sum2/k<<"/"<<sum/k<<'\n';
}