Poj 2096 (dp求期望) 概率dp

本文介绍了使用动态规划解决数学期望问题的方法,以两个实例详细解释了如何通过状态转移方程求解期望值,适用于软件子系统故障查找和游戏骰子掷掷次数的期望计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

Poj 2096 (dp求期望)

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

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

  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)  收藏  举报

第二个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 的子系统中

 


  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求数学期望的题目,也算是入个门吧...

  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. }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值