UVA_10417
如果我们设事件Ai为第1个人带来的是第i类gift,事件B为所有人的gift放一起呈现出题目中给出的每类多少个那种状态。那么P(Ai|B)就对应表示在当前这种状态下第1个人带来的是第i类gift的概率,那么剩下的问题就是把这个概率算出来就好了,然后除以第i类gift的个数就是拿1个第i类的gift且拿成功的概率。
根据条件概率的公式有P(Ai|B)=P(AiB)/P(B),P(AiB)表示事件Ai和B同时发生的概率。由于原始gift状态的子状态个数有限,我们可以指定一个放礼物的顺序(或者拿礼物的顺序)然后进行动规来求各个状态的概率即可。
于是我们不妨规定从第一个人开始,每人拿回去自己的礼物,拿空为止。设f[i][j]表示能达到第i个人面临礼物状态j时这种情况的概率,j不难表示,用13进制即可,剩下就是如何转移状态了,应该有f[i][j]=SUM{g[i][Ai]*f[i-1][j-Ai]},其中g[i][Ai]为第i个人带来的是Ai这个gift的概率,j-Ai表示第i个人拿走Ai后剩余的gift的状态,并不是直接做减法。
现在有了达到各个状态的概率了,那么P(AiB)怎么表示呢?应该为g[1][Ai]*f[2][k],其中g[1][Ai]为第1个人带来的是Ai这个gift的概率,k为第1个人拿走Ai后的剩余gift的状态。P(B)怎么表示呢?应该为f[1][k],其中k为原始的gift的状态。
#include<stdio.h>
#include<string.h>
#define MAXN 13
#define MAXB 6
#define MAXD 350000
int vis[MAXN][MAXD], a[MAXB], b[MAXB], N, M, gift[MAXB];
double f[MAXN][MAXD], g[MAXN][MAXB];
double dfs(int cur, int st)
{
int i, j, k;
double ans = 0;
if(vis[cur][st])
return f[cur][st];
k = st;
for(i = 5; i > 0; i --)
{
a[i] = k % 13;
k /= 13;
}
for(i = 1; i <= 5; i ++)
if(a[i])
{
-- a[i];
for(j = 1, k = 0; j <= 5; j ++)
k = k * 13 + a[j];
ans += dfs(cur + 1, k) * g[cur][i];
++ a[i];
}
vis[cur][st] = 1;
return f[cur][st] = ans;
}
void solve()
{
int i, j, k, box;
double max, ans, res;
scanf("%d", &N);
for(i = 1; i <= 5; i ++)
scanf("%d", &gift[i]);
for(i = 1; i <= N; i ++)
for(j = 1; j <= 5; j ++)
scanf("%lf", &g[i][j]);
for(i = 1, k = 0; i <= 5; i ++)
k = k * 13 + gift[i];
memset(vis, 0, sizeof(vis));
vis[N + 1][0] = 1;
f[N + 1][0] = 1;
res = dfs(1, k);
max = -1;
for(i = 1; i <= 5; i ++)
if(gift[i])
{
-- gift[i];
for(j = 1, k = 0; j <= 5; j ++)
k = k * 13 + gift[j];
++ gift[i];
ans = f[2][k] * g[1][i] / gift[i];
if(ans / res > max + 1e-9)
{
max = ans / res;
box = i;
}
}
printf("%d %.3lf\n", box, max);
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
solve();
}
return 0;
}