1. 程式人生 > >POJ - 2096 Collecting Bugs(概率dp)

POJ - 2096 Collecting Bugs(概率dp)

軟件 tar 可以轉化 答案 一個bug 精度 ron 現在 pan

https://vjudge.net/problem/POJ-2096

題意

一個軟件有s個子系統,會產生n種bug。某人一天發現一個bug,這個bug屬於某種bug,發生在某個子系統中。求找到所有的n種bug,且每個子系統都找到bug,這樣所要的天數的期望。需要註意的是:bug的數量是無窮大的,所以發現一個bug,出現在某個子系統的概率是1/s,屬於某種類型的概率是1/n。

分析

dp[i][j]表示已經找到i種bug,並存在於j個子系統中,要達到目標狀態的天數的期望。顯然,dp[n][s]=0,因為已經達到目標了。而dp[0][0]就是我們要求的答案。
dp[i][j]狀態可以轉化成以下四種:

dp[i][j] 發現一個bug屬於已經找到的i種bug和j個子系統中
dp[i+1][j] 發現一個bug屬於新的一種bug,但屬於已經找到的j種子系統
dp[i][j+1] 發現一個bug屬於已經找到的i種bug,但屬於新的子系統
dp[i+1][j+1]發現一個bug屬於新的一種bug和新的一個子系統
以上四種的概率分別為:
p1 = i*j / (n*s)
p2 = (n-i)*j / (n*s)
p3 = i*(s-j) / (n*s)
p4 = (n-i)*(s-j) / (n*s)
又有:期望可以分解成多個子期望的加權和,權為子期望發生的概率,即 E(aA+bB+...) = aE(A) + bE(B) +...
所以:dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1;
整理得:dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 )= ( 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 )

需要對式子化簡一下,不然精度似乎不夠。。

#include <iostream>
#include 
<cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <ctime> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #include <bitset> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(a, b) memset(a, b, sizeof(a)) #define pb push_back #define mp make_pair #define pii pair<int, int> #define IOS ios::sync_with_stdio(0);cin.tie(0); #define random(a, b) rand()*rand()%(b-a+1)+a #define pi acos(-1.0) const ll INF = 0x3f3f3f3f3f3f3f3fll; const int inf = 0x3f3f3f3f; const int maxn = 1e5+10; const int maxm = 1e5+10; const ll mod = 1e9+7; double dp[1010][1010]; int main(){ #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("output.txt", "w", stdout); #endif int n,s; scanf("%d%d",&n,&s); dp[n][s]=0.0; int ns=n*s; for(int i=n;i>=0;i--){ for(int j=s;j>=0;j--){ if(i==n&&j==s) continue; // dp[i][j]=dp[i][j]*(1.0*i*j/(n*s))+dp[i+1][j]*(1.0*(n-i)*j/(n*s)) // +dp[i][j+1]*(1.0*i*(s-j)/(n*s))+dp[i+1][j+1]*(1.0*(n-i)*(s-j)/(n*s))+1; 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 ); } } printf("%.4f\n",dp[0][0]); return 0; }

POJ - 2096 Collecting Bugs(概率dp)