奖励关(NKOI 数学期望)

在一款电子游戏中,玩家面临一个奖励关,需要根据宝物出现的概率和得分规则,选择最优策略以获得最高平均得分。文章通过数学期望模型,解决如何在已知宝物种类、得分和前提条件的情况下,最大化平均得分的问题。给出的代码示例虽然有缺陷,但展示了如何利用状态压缩和二进制技巧来处理这个问题。
P2084【SCOI2008 Day1】奖励关
时间限制 : 10000 MS   空间限制 : 165536 KB

问题描述

你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。

宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。也就是说,即使前k-1 次系统都抛出宝物1(这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n。

获取第 i 种宝物将得到Pi分,但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i 种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。注意,Pi 可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。

假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?

输入格式

第一行为两个正整数k 和n,即宝物的数量和种类。以下n行分别描述一种宝物,其中第一个整数代表分值,随后的整数依次代表该宝物的各个前提宝物(各宝物编号为1到n),以0结尾。

输出格式

输出一个实数,保留六位小数,即在最优策略下平均情况的得分。

样例输入

样例输入1:
1 2
1 0
2 0
样例输入2:
6 6
12 2 3 4 5 0
15 5 0
-2 2 4 5 0
-11 2 5 0
5 0
1 2 4 5 0

样例输出

样例输出1:
1.500000
样例输出2:
10.023470

提示

【数据规模】
1 <= k <= 100, 1 <= n <= 15,分值为[-10^6,10^6]内的整数。

 

#include<iostream>
#include<cstdio>
using namespace std;
int k,n,BIT[20],s[20],maxx;
double f[105][17000],p[20];
int main()
{
    int i,t,j;
    scanf("%d%d",&k,&n);
    for(i=1;i<=n;i++)
    BIT[i]=1<<(i-1);
    
    maxx=1<<(n-1);
    for(i=1;i<=n;i++)
    {
        scanf("%lf",&p[i]);
        scanf("%d",&t);
        while(t!=0)
        {
            s[i]|=(1<<(t-1));
            scanf("%d",&t);
        }
    }
    for(i=k-1;i>=0;i--)
    for(j=maxx;j>=0;j--)
    for(t=1;t<=n;t++)
    if((j&s[t])==s[t])f[i][j]+=max((f[i+1][j|BIT[t]]+p[t]),f[i+1][j])/double(n);
    else f[i][j]+=f[i+1][j]/double(n);
    printf("%.6lf\n",f[0][0]);
    return 0;    

(代码有缺陷)

    这又是一个典型的数学期望问题,但是有趣的是n的取值范围,只有15,再考虑到再次出现了这种经典的条件性选择的限制(即类似于拓扑序列,在x出现之前必须先出现x1,x2,x3....),我们很容易想到记录每种奖励的出现情况(状态),再结合n<=15,这个奇妙的数据范围,很容易想到用状态压缩(二进制)来处理。

    于是只需要定义f[i][j]为第i天,奖励领取情况为j(把j看成二进制 )记录 奖励领取情况时到终点时期望获得的最大得分,然后,f[i][j]的值受到n个f[i+1][j']的影响(其中j'代表了这一天选取宝物之后,宝物领取情况改变后的状态)

    即f[i][j]=求和max((f[i+1][j']+p[k]),f[i+1][j])/n;(吃得起的情况下,吃与不吃)

    若吃不起,则f[i][j]+=f[i+1][j]/n(只好不吃)。

     这个地方需要注意的是,我们用到了一个小技巧,即是s[]数组的使用,把s[]数组存的数看做二进制,s[i]表示要吃到第i个宝物,必须先吃到那些宝物,需要吃到的宝物相应的二进制位置上记录为1。这个时候,只需要j&s[i],如果等于s[i],说明s[i]被完整地“包含”在了j中,说明符合吃的条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值