• UVA 10417 Gift Exchanging


    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;
    }


  • 相关阅读:
    洛谷P5173 传球(暴力)
    uoj#402. 【CTSC2018】混合果汁(主席树+二分)
    uoj#401. 【CTSC2018】青蕈领主(分治FFT)
    uoj#400. 【CTSC2018】暴力写挂(边分治)
    uoj#399. 【CTSC2018】假面(概率期望)
    P4769 [NOI2018]冒泡排序(dp)
    洛谷P3688/uoj#291. [ZJOI2017]树状数组
    uoj#290. 【ZJOI2017】仙人掌(数数+仙人掌+树形dp)
    Git环境部署
    mysql修改密码
  • 原文地址:https://www.cnblogs.com/staginner/p/2287777.html
Copyright © 2020-2023  润新知