如何遞推求解一個隨機變數的數學期望?(以題為例)
摘要:
本文主要講解了怎樣運用遞推法求解一個離散型隨機變數的數學期望,首先介紹數學期望,然後是數學期望的性質,最後通過例題的形式,分析如何利用遞推及性質求解一個離散型隨機變數的數學期望。
首先應該知道數學期望的定義:
數學期望(mean)(亦簡稱期望)是試驗中每次可能結果的概率乘以其結果的總和,是最基本的數學特徵之一。它反映隨機變數平均取值的大小。因為隨機變數分為離散型和連續性,對應的數學期望也有不同的求法。
簡單來說一個離散型隨機變數的例子,設投擲一個色子的到的數為隨機變數x,得到的數可能是1,2,3,4,5,6,它們的概率都是1/6,那麼x的數學期望就是(1/6 * 1)+(1/6 * 2)+(1/6 * 3)+(1/6 * 4)+(1/6 * 5)+(1/6 * 6) = 21/6;
然後對應數學期望的線性性質有:
E(C) = C;常數的期望等於期望本身。
E(CX) = CE(X);
E(X + Y) = E(X) + E(Y);也就是說和的期望等於期望的和。
最後,也是最難的一步,根據不同的情況寫出遞推式,最後求解期望。
下面題為例,側重寫出遞推式的過程。
題意
給出一個n,n隨機的除以它的一個因子c變成n/c計數一次,問如此重複隨機的除以它的一個因子直至最後變成1為止 所除的次數的數學期望。
解題思路
定義狀態dp[i]為:數字i迴圈的隨機的除以它的一個因子變為1所需次數的數學期望
最後dp[n]即為所求;
設n的因子從小到大依次是1,a2,a3,a4...aN
dp[n] = (dp[1] + 1)/N + (dp[a2] +1)/N + (dp[a3] + 1)/N + (dp[a4] + 1) /N + ... + (dp[aN-1] + 1)/N + (dp[n] + 1)/N;
化簡可得:
dp[n] = (dp[a2] + dp[a3] + dp[a4] + ... + dp[aN-1] + N) / (N - 1);
程式碼如下:
1 #include <cstdio> 2 3 const int maxn = 100000+ 10; 4 double dp[maxn]; 5 int main() 6 { 7 dp[1] = 0; 8 for(int i = 2; i < maxn; i++) { 9 double sum = 0; 10 int cnt = 0; 11 for(int j = 1; j * j <= i; j++) { 12 if(i % j == 0) { 13 sum += dp[j]; 14 cnt++; 15 if(i / j != j) { 16 sum += dp[i/j]; 17 cnt++; 18 } 19 } 20 } 21 dp[i] = (sum + cnt)/(cnt-1); 22 } 23 int T, t = 1; 24 int n; 25 scanf("%d", &T); 26 while(T--) { 27 scanf("%d", &n); 28 printf("Case %d: %.7lf\n", t++, dp[n]); 29 } 30 return 0; 31 }
題意
輸入一年的天數,問至少有幾個人才能保證兩個人生日是同一天的概率超過%50.
解題思路
至少有幾個人才能保證兩個人的生日是同一天的概率超過%50,我們可以反向思考,至少幾個人才能保證每個人的生日都不重複的概率低於%50.
每個人的生日可能是1/n,那麼第i個人的生日不同於之前所有人的概率就是(n - i) / n,那麼整個事件發生的概率就是這i個人的概率的乘積小於等於%50.
1 #include <cstdio> 2 int main() 3 { 4 int n; 5 int T, t = 1; 6 scanf("%d", &T); 7 while(T--) { 8 scanf("%d", &n); 9 double ans = 1.0; 10 for(int i = 1; ; i++) { 11 ans *= (double)(n - i) / n; 12 if(ans <= 0.5) { 13 printf("Case %d: %d\n", t++, i); 14 break; 15 } 16 } 17 } 18 return 0; 19 }
題意
輸入n和n個數,每個位置上的數表示該格子的金幣數,從第一個格子出發,每次投擲一個色子,出現多少就意味著向後走幾步,走到那個格子就將其對應的金幣收走,問最後獲得金幣數的數學期望。
解題思路
定義狀態dp[i]從第i個格子走到第n個格子所獲得金幣數的數學期望
最後dp[1]即為答案。
首先應該想到的是第i個格子的數學期望是它能走到的格子的數學期望除以總的能走到的格子數 之和,即dp[i] = dp[i]/cnt + dp[i + 1]/cnt + dp[i +cnt]/cnt;其中cnt為它能走到的格子數。
然後逆著遞推計算,最後輸出dp[1]即可。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn = 110; 6 double dp[maxn]; 7 int n; 8 9 int main() 10 { 11 int T, t = 1; 12 scanf("%d", &T); 13 while(T--) { 14 scanf("%d", &n); 15 for(int i = 1; i <= n; i++) { 16 scanf("%lf", &dp[i]); 17 } 18 19 for(int i = n - 1; i >= 1; i--) { 20 int cnt = min(n - i, 6); 21 for(int j = 1; j <= cnt; j++) { 22 dp[i] += dp[i + j]/(1.0*cnt); 23 } 24 } 25 printf("Case %d: %.7lf\n",t++, dp[1]); 26 } 27 return 0; 28 }
在演算法競賽中,經常會出一些涉及一些概率論的知識,程式碼不難實現,關鍵是通過題意找出遞推關係即可。