石頭剪刀布
題意:
桌面上有 個石頭, 個剪刀和 個布。
每次等概率選擇兩個(種類)不同的物品進行剪刀石頭布,將輸掉的物品移出桌面。
求最後桌面上只剩下石頭的概率,和只剩下剪刀的概率,和只剩下布的概率。保留八位小數。
解法:
用 表示剩餘 個石頭, 個剪刀和 個布的概率。則狀態轉移方程爲 其中 其他情況類似。
參考代碼:
#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;
}