Poj 2096 (dp求期望) 概率dp

来源:互联网 发布:excel下拉菜单关联数据 编辑:程序博客网 时间:2024/04/30 20:16
 

Poj 2096 (dp求期望)

分类: 动态规划 1581人阅读 评论(10) 收藏 举报

  这题虽然代码很简单,但这是我第一题用dp求数学期望的题目,也算是入个门吧...

[cpp] view plaincopyprint?
  1. /** 
  2.     dp求期望的题。 
  3.     题意:一个软件有s个子系统,会产生n种bug。 
  4.     某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。 
  5.     求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。 
  6.     需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s, 
  7.     属于某种类型的概率是1/n。 
  8.     解法: 
  9.     dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。 
  10.     显然,dp[n][s]=0,因为已经达到目标了。而dp[0][0]就是我们要求的答案。 
  11.     dp[i][j]状态可以转化成以下四种: 
  12.         dp[i][j]    发现一个bug属于已经找到的i种bug和j个子系统中 
  13.         dp[i+1][j]  发现一个bug属于新的一种bug,但属于已经找到的j种子系统 
  14.         dp[i][j+1]  发现一个bug属于已经找到的i种bug,但属于新的子系统 
  15.         dp[i+1][j+1]发现一个bug属于新的一种bug和新的一个子系统 
  16.     以上四种的概率分别为: 
  17.     p1 =     i*j / (n*s) 
  18.     p2 = (n-i)*j / (n*s) 
  19.     p3 = i*(s-j) / (n*s) 
  20.     p4 = (n-i)*(s-j) / (n*s) 
  21.     又有:期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+...) = aE(A) + bE(B) +... 
  22.     所以: 
  23.     dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1; 
  24.     整理得: 
  25.     dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 ) 
  26.             = ( n*s + (n-i)*j*dp[i+1,j] + i*(s-j)*dp[i,j+1] + (n-i)*(s-j)*dp[i+1,j+1] )/( n*s - i*j ) 
  27. **/  
  28. #include <cstdio>  
  29. #include <iostream>  
  30.   
  31. using namespace std;  
  32.   
  33. double dp[1005][1005];  
  34.   
  35. int main()  
  36. {  
  37.     int n, s, ns;  
  38.   
  39.     cin >> n >> s;  
  40.     ns = n*s;  
  41.     dp[n][s] = 0.0;  
  42.     for (int i = n; i >= 0; i--)  
  43.         for (int j = s; j >= 0; j--)  
  44.         {  
  45.             if ( i == n && j == s ) continue;  
  46.             dp[i][j] = ( ns + (n-i)*j*dp[i+1][j] + i*(s-j)*dp[i][j+1] + (n-i)*(s-j)*dp[i+1][j+1] )/( ns - i*j );  
  47.         }  
  48.     printf("%.4lf\n", dp[0][0]);  
  49.   
  50.     return 0;  
  51. }  


 

Zoj 3329 (dp求期望)

分类: 动态规划 1376人阅读 评论(6) 收藏 举报
游戏c

第二个dp求数学期望的题,如果看不懂,请看我的第一个dp求期望的题(Poj 2096)

令 f[i][j] 表示已经找到了 i 种 bug,且 j 个子系统至少包含一个 bug,距离完成目标需要的时间的期望。

目标状态是 f[0][0]


再过一天找到一个 bug 可能是如下的情况:

        1. 这个 bug 的种类是 已经找到的 并且 出现在 已经找到 bug 的子系统中

        2. 这个 bug 的种类是 已经找到的 并且 出现在 没有找到 bug 的子系统中

        3. 这个 bug 的种类是 没有找到的 并且 出现在 已经找到 bug 的子系统中

        4. 这个 bug 的种类是 没有找到的 并且 出现在 没有找到 bug 的子系统中

 


[cpp] view plaincopyprint?
  1. /** 
  2.     dp求期望的题。 
  3.     题意: 
  4.     有三个均匀的骰子,分别有k1,k2,k3个面,初始分数是0, 
  5.     当掷三个骰子的点数分别为a,b,c的时候,分数清零,否则分数加上三个骰子的点数和, 
  6.     当分数>n的时候结束。求需要掷骰子的次数的期望。 
  7.     题解: 
  8.     设 E[i]表示现在分数为i,到结束游戏所要掷骰子的次数的期望值。 
  9.     显然 E[>n] = 0; E[0]即为所求答案; 
  10.     E[i] = ∑Pk*E[i+k] + P0*E[0] + 1; (Pk表示点数和为k的概率,P0表示分数清零的概率) 
  11.     由上式发现每个 E[i]都包含 E[0],而 E[0]又是我们要求的,是个定值。 
  12.     设 E[i] = a[i]*E[0] + b[i]; 
  13.     将其带入上面的式子: 
  14.     E[i] = ( ∑Pk*a[i+k] + P0 )*E[0] + ∑Pk*b[i+k] + 1; 
  15.     显然, 
  16.     a[i] = ∑Pk*a[i+k] + P0; 
  17.     b[i] = ∑Pk*b[i+k] + 1; 
  18.     当 i > n 时: 
  19.     E[i] = a[i]*E[0] + b[i] = 0; 
  20.     所以 a[i>n] = b[i>n] = 0; 
  21.     可依次算出 a[n],b[n]; a[n-1],b[n-1] ... a[0],b[0]; 
  22.     则 E[0] = b[0]/(1 - a[0]); 
  23. **/  
  24.   
  25. #include <cstdio>  
  26. #include <cstring>  
  27. #include <iostream>  
  28.   
  29. using namespace std;  
  30.   
  31. int main()  
  32. {  
  33.     int    nc, n, ks, k1, k2, k3, a, b, c;  
  34.     double p0, p[20];  
  35.   
  36.     cin >> nc;  
  37.     while ( nc-- )  
  38.     {  
  39.         cin >> n >> k1 >> k2 >> k3 >> a >> b >> c;  
  40.         ks = k1 + k2 + k3;  
  41.         p0 = 1.0 / (k1*k2*k3);  
  42.         memset(p, 0, sizeof(p));  
  43.   
  44.         for (int i = 1; i <= k1; i++)  
  45.             for (int j = 1; j <= k2; j++)  
  46.                 for (int k = 1; k <= k3; k++)  
  47.                 {  
  48.                     if ( i != a || j != b || k != c )  
  49.                         p[i+j+k] += p0;  
  50.                 }  
  51.   
  52.         double a[520] = {0}, b[520] = {0};  
  53.         for (int i = n; i >= 0; i--)  
  54.         {  
  55.             for (int k = 3; k <= ks; k++)  
  56.             {  
  57.                 a[i] += a[i+k]*p[k];  
  58.                 b[i] += b[i+k]*p[k];  
  59.             }  
  60.             a[i] += p0;  
  61.             b[i] += 1;  
  62.         }  
  63.         printf("%.15lf\n", b[0]/(1 - a[0]) );  
  64.     }  
  65.     return 0;  
  66. }  
 

Poj 2096 (dp求期望)

分类: 动态规划 1580人阅读 评论(10) 收藏 举报

  这题虽然代码很简单,但这是我第一题用dp求数学期望的题目,也算是入个门吧...

[cpp] view plaincopyprint?
  1. /** 
  2.     dp求期望的题。 
  3.     题意:一个软件有s个子系统,会产生n种bug。 
  4.     某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。 
  5.     求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。 
  6.     需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s, 
  7.     属于某种类型的概率是1/n。 
  8.     解法: 
  9.     dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。 
  10.     显然,dp[n][s]=0,因为已经达到目标了。而dp[0][0]就是我们要求的答案。 
  11.     dp[i][j]状态可以转化成以下四种: 
  12.         dp[i][j]    发现一个bug属于已经找到的i种bug和j个子系统中 
  13.         dp[i+1][j]  发现一个bug属于新的一种bug,但属于已经找到的j种子系统 
  14.         dp[i][j+1]  发现一个bug属于已经找到的i种bug,但属于新的子系统 
  15.         dp[i+1][j+1]发现一个bug属于新的一种bug和新的一个子系统 
  16.     以上四种的概率分别为: 
  17.     p1 =     i*j / (n*s) 
  18.     p2 = (n-i)*j / (n*s) 
  19.     p3 = i*(s-j) / (n*s) 
  20.     p4 = (n-i)*(s-j) / (n*s) 
  21.     又有:期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+...) = aE(A) + bE(B) +... 
  22.     所以: 
  23.     dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1; 
  24.     整理得: 
  25.     dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 ) 
  26.             = ( n*s + (n-i)*j*dp[i+1,j] + i*(s-j)*dp[i,j+1] + (n-i)*(s-j)*dp[i+1,j+1] )/( n*s - i*j ) 
  27. **/  
  28. #include <cstdio>  
  29. #include <iostream>  
  30.   
  31. using namespace std;  
  32.   
  33. double dp[1005][1005];  
  34.   
  35. int main()  
  36. {  
  37.     int n, s, ns;  
  38.   
  39.     cin >> n >> s;  
  40.     ns = n*s;  
  41.     dp[n][s] = 0.0;  
  42.     for (int i = n; i >= 0; i--)  
  43.         for (int j = s; j >= 0; j--)  
  44.         {  
  45.             if ( i == n && j == s ) continue;  
  46.             dp[i][j] = ( ns + (n-i)*j*dp[i+1][j] + i*(s-j)*dp[i][j+1] + (n-i)*(s-j)*dp[i+1][j+1] )/( ns - i*j );  
  47.         }  
  48.     printf("%.4lf\n", dp[0][0]);  
  49.   
  50.     return 0;  
  51. }