Gift Exchanging - UVa 10417 概率dp

题意:给你你的n个小伙伴一人给你带了一种类型的礼物,告诉你各个礼物的数量,和每个小伙伴给哪种礼物的概率,问你选择哪种类型的礼物最有可能是第一个人给的,这个概率是多少。

思路:设A为第一个小伙伴给某种礼物的概率,B为所有人给的礼物恰好是给定的数目的概率P(A|B)=P(AB)/P(B)。B的概率由dp递推得出。最后还得除以这个礼物的数目,再找到最大的这个概率。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
double dp[100010],p[13][5],eps=1e-10;
ll point[100010],S_num[100010],S_pos,pow13[10];
map<ll,int> match;
int T,t,n,num[5];
int dcmp(double x)
{
    return (x>eps)-(x<-eps);
}
bool check(ll S,int pos)
{
    ll ret=S%pow13[pos+1]/pow13[pos];
    if(ret+1<=num[pos])
      return true;
    else
      return false;
}
int get(ll S,int ret)
{
    int k=match[S];
    if(k>0)
      return k;
    else
    {
        match[S]=++S_pos;
        point[S_pos]=S;
        S_num[S_pos]=ret;
        dp[S_pos]=0;
        return S_pos;
    }
}
void solve(ll S,int pos)
{
    int i,j,k1,k2,ret;
    k1=match[S];
    ret=S_num[k1]+1;
    k2=get(S+pow13[pos],ret);
    dp[k2]+=dp[k1]*p[ret][pos];
    //printf("%d %d   %lf %lf %lf\n",k1,k2,dp[k2],dp[k1],p[ret][pos]);
}
int main()
{
    int i,j,k,pos;
    double A,B,MAXN,p2;
    ll MAXS,S;
    pow13[0]=1;
    for(i=1;i<=6;i++)
       pow13[i]=pow13[i-1]*13;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        match.clear();
        scanf("%d",&n);
        for(i=0;i<5;i++)
           scanf("%d",&num[i]);
        for(i=0;i<n;i++)
           for(j=0;j<5;j++)
              scanf("%lf",&p[i][j]);
        for(j=0;j<5;j++)
           p[n][j]=p[0][j];
        point[1]=0;
        S_num[1]=0;
        S_pos=1;
        match[0]=1;
        dp[1]=1;
        //printf("%.3f\n",dp[1]);
        for(i=1;i<=S_pos;i++)
           for(j=0;j<5;j++)
             if(check(point[i],j))
               solve(point[i],j);
        for(i=1;i<=S_pos;i++)
        {
            //printf("%d  %lld %lld %.3f\n",i,point[i],S_num[i],dp[i]);
        }
        B=dp[S_pos];
        MAXN=0;
        MAXS=0;
        for(i=0;i<=4;i++)
           MAXS+=pow13[i]*num[i];
        for(i=0;i<=4;i++)
           if(num[i]>0)
           {
               S=MAXS-pow13[i];
               k=match[S];
               p2=p[0][i]*dp[k]/B/num[i];
               if(dcmp(p2-MAXN)>0)
               {
                   MAXN=p2;
                   pos=i;
               }
           }
        printf("%d %.3f\n",pos+1,MAXN);
    }
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值