SGU 495 Kids and Prizes:期望dp / 概率dp / 推公式

Leohh發表於2017-09-21

題目連結:http://acm.sgu.ru/problem.php?contest=0&problem=495

題意:

  有n個禮物盒,m個人。

  最開始每個禮物盒中都有一個禮物。

  m個人依次隨機選一個盒子,如果有禮物就拿走,然後放回空盒子。

  問你所有人得到總禮物數的期望。

 

題解:

  三種做法:期望dp,概率dp,推公式

 

  一、期望dp

    表示狀態:

      dp[i] = 該第i個人拿箱子時的總禮物的期望

    找出答案:

      ans = dp[m]

    如何轉移:

      對於第i個人,拿到禮物或沒拿到。

      (1)φ(沒拿到) = dp[i]  P(沒拿到) = dp[i]/n

      (2)φ(拿到) = dp[i]+1  P(拿到) = (n-dp[i])/n

      綜上:dp[i+1] = dp[i] * dp[i]/n + (dp[i]+1) * (n-dp[i])/n

    邊界條件:

      dp[0] = 0

      還沒開始拿的時候禮物數為0

 

  二、概率dp

    表示狀態:

      dp[i] = 第i個人拿到禮物的概率

    找出答案:

      ans = ∑ dp[i]

      每個人得到禮物的概率 * 得到禮物的數量(為1) 之和。

    如何轉移:

      對於第i個人,拿到禮物或沒拿到。

      (1)沒拿到:dp[i+1]依然等於dp[i],沒拿到禮物的概率為1-dp[i].

      (2)拿到:dp[i+1] = dp[i] - 1/n,拿到的概率為dp[i].

      綜上:dp[i+1] = dp[i] * (1 - dp[i]) + (dp[i] - 1/n) * dp[i]

    邊界條件:

      dp[0] = 1

      所有盒子裡都有禮物,第0個人一定拿到禮物。

 

  三、推公式

    m個人是獨立的。

    對於每個禮物不被人選中的概率為((n-1)/n)^m

    那麼不被選中的禮物數的期望就是 n*((n-1)/n)^m

    所以答案就是 n-n*((n-1)/n)^m

 

AC Code(expectation):

 1 // state expression:
 2 // dp[i] = expectation
 3 // i: considering ith person
 4 //
 5 // find the answer:
 6 // ans = dp[m]
 7 //
 8 // transferring:
 9 // dp[i+1] = dp[i] * dp[i]/n + (dp[i]+1) * (n-dp[i])/n
10 //
11 // boundary:
12 // dp[0] = 0
13 #include <iostream>
14 #include <stdio.h>
15 #include <string.h>
16 #define MAX_M 100005
17 
18 using namespace std;
19 
20 int n,m;
21 double dp[MAX_M];
22 
23 int main()
24 {
25     scanf("%d%d",&n,&m);
26     for(int i=0;i<m;i++)
27     {
28         dp[i+1]=dp[i]*dp[i]/n+(dp[i]+1.0)*(n-dp[i])/n;
29     }
30     printf("%.10f\n",dp[m]);
31 }

 

AC Code(probability):

 1 // state expression:
 2 // dp[i] = probability
 3 // i: ith person got a gift
 4 //
 5 // find the answer:
 6 // sigma dp[i]
 7 //
 8 // transferring:
 9 // dp[i+1] = dp[i] * (1 - dp[i]) + (dp[i] - 1/n) * dp[i]
10 //
11 // boundary:
12 // dp[0] = 1
13 #include <iostream>
14 #include <stdio.h>
15 #include <string.h>
16 #define MAX_M 100005
17 
18 using namespace std;
19 
20 int n,m;
21 double ans=0;
22 double dp[MAX_M];
23 
24 int main()
25 {
26     scanf("%d%d",&n,&m);
27     dp[0]=1;
28     for(int i=0;i<m;i++)
29     {
30         dp[i+1]=dp[i]*(1.0-dp[i])+(dp[i]-1.0/n)*dp[i];
31         ans+=dp[i];
32     }
33     printf("%.10f\n",ans);
34 }

 

AC Code(公式):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <math.h>
 5 
 6 using namespace std;
 7 
 8 int n,m;
 9 
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     printf("%.10f\n",n-n*pow((n-1.0)/n,m));
14 }

 

相關文章