题意:
有n类bug, s种系统,每个bug可以属于一种系统,一类bug。
每天可以找到一个新的bug,这个bug属于每一类bug的概率相同都是 ,属于每一种系统的概率也是相同的,都是
。
那么要使得每一类bug都至少有一个bug,每一个系统也至少有一个bug,所需要的天数的期望是多少。
输入n和s输出天数的期望
思路:
考虑如果没有s种系统,只需要找到n类不同的bug,那么就非常的简单,这个期望就是n
对于概率dp都是倒着推导的,dp[i][j]代表已经找到了i类bug,j种系统,需要的期望。
很明显dp[n][s] = 0,对于dp[i][j]来说,下一个状态可能有四种情况。
1 找到的这个bug的类和系统都是以前出现过的,状态:dp[i][j] , 概率:i*j / (n*s)
2 这个bug的类没有出现过,系统出现过,状态:dp[i+1][j],概率:(n-i)*j / (n*s)
3 这个bug的类出现过,系统没有出现过,状态:dp[i][j+1] 概率 i * (s -j ) / (n*s)
4 这个bug的类个系统都没有出现过, 状态: dp[i+1][j+1] 概率: (n-i) * (s - j) / (n *s)
状态转移方程:dp[i][j] = dp[i][j] * (i*j / (n*s)) + dp[i+1][j] * ((n-i)*j / (n*s)) + dp[i][j+1] * ( i * (s -j ) / (n*s)) + dp[i+1][j+1] * ((n-i) * (s - j) / (n *s)) + 1
+1 是因为步数应该加一,因为多了一天了。
左右两边全部都乘上n*s。 dp[i][j] * n *s = dp[i][j] * i *j + dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s
合并dp[i][j]
dp[i][j] (n*s - i *j ) = dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s
左右两边都除以(n * s - i * j )
dp[i][j] = (dp[i+1][j] *(n-i)*j + dp[i][j+1] * i * (s -j ) + dp[i+1][j+1] * (n-i ) * (s-j) + n *s ) / (n*s - i * j)
#pragma warning(disable:4996)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 505;
const ll mod = 10000;
double dp[1005][1005];
int main()
{
int n, i, j, s;
scanf("%d%d", &n, &s);
memset(dp, 0, sizeof(dp));
for (i = n; i >= 0; i--)
{
for (j = s; j >= 0; j--)
{
if (i == n && j == s)continue;
dp[i][j] = (dp[i + 1][j + 1] * (n - i)*(s - j) + dp[i + 1][j] * (n - i)*j +
dp[i][j + 1] * i*(s - j) + n * s) / (n*s - i * j);
//化简后的状态转移方程
}
}
printf("%.4lf\n", dp[0][0]);
return 0;
}