Problem
vjudge.net/contest/151678#problem/Q
Reference
blog.csdn.net/xingyeyongheng/article/details/25179481
blog.csdn.net/zy691357966/article/details/46776199(概率dp入门)
www.cnblogs.com/kuangbin/archive/2012/10/02/2710606.html(概率dp总结 by kuangbin)
wenku.baidu.com/view/1c41152de2bd960590c677a8.html(《信息学竞赛中概率问题求解初探》by 梅诗珂)
wenku.baidu.com/view/90adb02acfc789eb172dc8a8.html(《浅析竞赛中一类数学期望问题的求解》 by 汤可因)
wenku.baidu.com/view/56147518a8114431b90dd81e.html(《有关概率和期望问题的研究》 by 鬲融)
Meaning
Ivan 每天找一个 bug。现有 s 个子系统、n 种 bug,在每一个子系统中找到 bug 的概率永远相同(因为有无数个,概率不变),找到任意种 bug 的概率也永远相同。
要求在每个子系统中都至少找到一个 bug、每个种类的 bug 至少找一个,求所需的天数的期望值。
Analysis
dp[i][j]:已在 i 个子系统中找到 bug,已找到 j 种 bug,为达目的仍需要的期望天数。
显然,对所有 i >= s、j >= n 的 dp[i][j],有:dp[i][j] = 0。
在 dp[i][j] 的状态下,再找一个 bug,可能转去 4 种状态:
1. dp[i+1][j+1]:在一个还没发现过 bug 的子系统中(新系统),找到一种还没发现过的 bug(新 bug),概率是:p1 = (s - i) * (n - j) / (n * s);
2. dp[i+1][j]:在一个还没发现过 bug 的子系统中(新系统),找到一种已经发现过的 bug(旧 bug),概率是:p2 = (s - i) * j / (n * s);
3. dp[i][j+1]:在一个已经发现过 bug 的子系统中(旧系统),找到一种还没发现过的 bug(新 bug),概率是:p3 = i * (n - j) / (n * s);
4. dp[i][j]:在一个已经发现过 bug 的子系统中(旧系统),找到一种已经发现过的 bug(旧 bug),概率是:p4 = i * j / (n * s)。
所以,dp[i][j] = p1 * dp[i+1][j+1] + p2 * dp[i+1][j] + p3 * dp[i][j+1] + p4 * dp[i][j] + 1
移项整理,有:dp[i][j] = (p1 * dp[i+1][j+1] + p2 * dp[i+1][j] + p3 * dp[i][j+1] + 1) / (1 - p4)
Code
#include <stdio.h>
#define N 1000
#define S 1000
double dp[N+2][S+2] = {{0.0}};
int main()
{
int n, s, i, j;
scanf("%d%d", &n, &s);
for(i=n; ~i; --i)
for(j=s; ~j; --j)
if(i != n || j != s)
{
int p1 = (n - i) * (s - j),
p2 = (n - i) * j,
p3 = i * (s - j),
p4 = i * j;
dp[i][j] = (
p1 * dp[i+1][j+1] +
p2 * dp[i+1][j] +
p3 * dp[i][j+1] +
n * s
) / (n * s - p4);
}
printf("%.4f\n", dp[0][0]);
return 0;
}