POJ2096 Collecting Bugs

一个软件有s个子系统,会产生n种bug。某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s,属于某种类型的概率是1/n。
数据范围1≤n,s≤2000。
TL:1s,ML:256Mb

计算期望E=∑所有可能需要的天数*概率
s种系统,n种bug,bug数量不限,求在每个子系统中都找到了bug,且每个bug都出现了的期望天数
思考能够描述状态空间的数组
在这个状态空间中,有找到了几种bug,和几个子系统中找到了bug两个问题(我们需要注意到,对于这s个子系统,究竟找到了哪种bug这是不重要的,因为题目没有限定在某个系统要找哪种bug,也没有限定某种bug要被找到多少次,为了使期望天数最小,我们贪心的想,每种bug我们只在某个子系统中找到一次,每个子系统只找到一次bug,但不幸的是)。
这样我们能够设置出这样的dp数组:f[i, j]表示找了i个bug,在j个子系统中找到bug的期望天数
这样我们可以想到4个情况推导到当前情况,f[i - 1, j], f[i, j - 1], f[i - 1, j - 1], f[i, j]
但是这样推导过来,我们在当前情况的1天的概率我们是知道的,但是这4中情况的总概率并不等于1,也就是说,在某个期望天数内出现当前状态的概率并不等于1,这意味着可能会有需要2天,3天...的概率,这样问题就变得复杂难算,
但是我们似乎没有更多的信息支持我们相出一个新的状态,这样我们只能换一种思考方式:

摘抄:对于期望 DP,我们一般采用逆序的方式来定义状态,即考虑从当前状态到达终点的期望代价。因为在大多数情况下,终点不唯一,而起点是唯一的

//链接:https://blog.sengxian.com/algorithms/probability-and-expected-value-dynamic-programming

对于现在什么都不会的身为蒟蒻的我,选择相信大佬,倒着退....这样我们存储的信息就变成了,距离期望天数还有多少天,也就是距离期望天数的剩余天数
1.在新的系统中找到了旧bug:f[i, j + 1]
2.在旧的系统中找到了新Bug:f[i + 1, j]
3.在旧的系统中找到了旧Bug:f[i, j]
4.在新的系统中找到了新bug:f[i + 1, j + 1]
由这四个状态向当前情况推导
对于概率的计算,分别是:
1.p1 = i * (s - j) / (n * s);
2.p2 = (n - i) * j / (n * s);
3.p3 = i * j / n * s;
4.p4 = (n - i) * (s - j) / (n * s)
然后根据E(aA+bB+cC+dD+...)=aEA+bEB+....;//a,b,c,d...表示概率,A,B,C...表示状态
所以最后的dp方程就是:
f[i, j] = p1 * f[i, j + 1] + p2 * f[i + 1, j] + p3 * f[i, j] + p4 * f[i + 1, j + 1] + 1;
==> f[i, j] - p3 * f[i, j] = p1 * f[i, j + 1] + p2 * f[i + 1, j] + p4 * f[i + 1, j + 1] + 1;
==> f[i, j] * (1 - p3) = p1 * f[i, j + 1] + p2 * f[i + 1, j] + p4 * f[i + 1, j + 1] + 1;
==> f[i, j] = (p1 * f[i, j + 1] + p2 * f[i + 1, j] + p4 * f[i + 1, j + 1] + 1) / (1 - p3);
初态:f[n][s] = 0;
末态:f[0][0]

 

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define uint unsigned int
 4 #define ull unsigned long long
 5 using namespace std;
 6 const int maxn = 1100;
 7 double f[maxn][maxn];
 8 int n, s; 
 9 double a, b, c, d;
10 //f[i, j]表示找了i个bug,在j个子系统中找到bug的期望天数 
11 inline int read() {
12     int x = 0, y = 1;
13     char ch = getchar();
14     while(!isdigit(ch)) {
15         if(ch == '-') y = -1;
16         ch = getchar();
17     }
18     while(isdigit(ch)) {
19         x = (x << 1) + (x << 3) + ch - '0';
20         ch = getchar();
21     }
22     return x * y;
23 }
24 
25 int main() {
26     memset(f, 0, sizeof(f));
27     n = read(), s = read();
28     for(int i = n; i >= 0; --i)
29         for(int j = s; j >= 0; --j) {
30             //4种情况:旧的系统中找到了新的bug,旧的系统中找到了旧的bug 
31             //新的系统中找到了新的bug,新的系统中找到了旧的bug 
32             if(i == n && j == s) continue;
33             a = 1.0 * j * (n - i) / (s * n);//旧系统,新bug
34             b = 1.0 * j * i / (s * n);//旧系统,旧bug
35             c = 1.0 * (s - j) * i / (s * n);//新系统,旧bug
36             d = 1.0 * (s - j) * (n - i) / (s * n);//新系统,新bug
37             f[i][j] = (a * f[i + 1][j] + c * f[i][j + 1] + d * f[i + 1][j + 1] + 1) / (1 - b);  
38         }
39     printf("%.4f\n", f[0][0]);
40     return 0;
41 }

 

posted @ 2018-07-08 20:48  YuWenjue  阅读(199)  评论(0编辑  收藏  举报