CodeForces-28C-Bath Queue-概率DP[ ICPC2016大连热身D]
题目地址 http://codeforces.com/problemset/problem/28/C
代码+注释
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; //前i个澡堂,一共j个人,最长队伍为k的概率 //dp[i][j][k] double dp[55][55][100]; int a[55]; double C[55][55]; void init() { C[0][0] = 1; for ( int i = 1; i <= 50; i++ ) { C[i][0] = 1; for (int j = 1; j <= i; j++) C[i][j] = C[i-1][j-1] + C[i-1][j]; } } int main() { int m,n; scanf("%d%d",&n,&m); init();//求组合数 memset(dp,0,sizeof(dp)); for ( int i = 1; i <= m ; i++ ) scanf("%d",&a[i]); dp[0][0][0] = 1; // dp初始化 for (int i = 1 ; i <= m; i++) { for (int j = 0; j <= n ; j++) { for ( int k = 0; k <= n; k++) { //枚举[i][j][k] //计算dp[i][j][k] int top = min(k*a[i],j); //只有当前澡堂最长队伍小于等于k时。才能转移 for (int c = 0 ; c <= top ; c++) //i澡堂中人数 { if (k*a[i]-a[i]+1 > c) // 如果当前 澡堂最大值不是k 只能从dp[i-1][j-c][k]转移 dp[i][j][k] += dp[i-1][j-c][k] * pow(i-1,j-c) / pow(i,j) * C[j][c]; else // 如果当前为k,可以从 dp[i-1][j-c][<=K]转移 for (int tt = 0; tt<=k ;tt++) dp[i][j][k] += dp[i-1][j-c][tt] * pow(i-1,j-c) / pow(i,j)* C[j][c]; } } } } double ans = 0; for (int i = 1 ; i <= n; i++) { ans += dp[m][n][i] * i; } printf("%.10f\n",ans); return 0; }