zoukankan      html  css  js  c++  java
  • [BZOJ1076][SCOI2008]奖励关解题报告|状压DP

      你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。 宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。也就是说,即使前k-1次系统都抛出宝物1(这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n。 获取第i种宝物将得到Pi分,但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。注意,Pi可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。 假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?

      其实题目有个地方刚开始没看懂...

      刚开始说了你必须在跑出下一个宝物之前做出选择,然后我以为和执行最优策略矛盾了...

      事实上你所得到的都是期望得分

      必须在跑出下一个宝物之前作出选择,是因为游戏的具体过程是由系统操作的我们不清楚

      而执行最优策略只要在系统执行的一些概率条件下 作出能够得到最大期望得分的操作

      我们考虑倒序DP

      枚举当前是哪一轮,以及作出选择之前n个数取与不取的状态是怎样的

      再枚举这一轮系统抛下的宝物是哪一件

      如果满足这个宝物可以取,就在取与不取之间作取舍,如果不可以取,就只能不取

      最后再思考一个问题

      题目中有一句话“现在决定不吃的宝物以后也不能再吃”,这个限制在DP过程中并没有体现

      另外要注意,这个条件限制存在仅当目前这个宝物可以吃,也就是我们有自主选择的权利

      然而仔细想一想便可知是不存在问题的

      因为当前可以吃的宝物,以后一定也可以吃,因为已经满足了前提宝物集合的条件

      然而现在吃掉,在以后还可以吃一些前提宝物集合为当前宝物的宝物

      所以当前吃掉一定比以后吃掉的策略要优秀

      所以在执行最优决策的过程中是不存在现在不吃以后吃的情况的~

     1 program bzoj1076;
     2 const maxn = 110;maxm = 32768;
     3 var i,k,n,x,j,p:longint;
     4     w:array[-1..maxn]of longint;
     5     a:array[-1..20,-1..20]of longint;
     6     vis:array[-1..20,-1..maxm]of boolean;
     7     f:array[-1..maxn,-1..maxm]of extended;
     8 
     9 function ok(x,y:longint):boolean;
    10 var i:longint;
    11     tmp:array[-1..20]of longint;
    12 begin
    13     for i:=1 to n do tmp[i]:=y >> (n-i) and 1;
    14     for i:=1 to a[x,0] do if tmp[a[x,i]]=0 then exit(false);
    15     exit(true);
    16 end;
    17 
    18 function max(a,b:extended):extended;
    19 begin
    20     if a>b then exit(a) else exit(b);
    21 end;
    22 
    23 begin
    24     readln(k,n);
    25         fillchar(a,sizeof(a),0);
    26     for i:=1 to n do
    27     begin
    28         read(w[i]);
    29         read(x);
    30         while x<>0 do
    31         begin
    32             inc(a[i,0]);
    33             a[i,a[i,0]]:=x;
    34             read(x);
    35         end;
    36         readln;
    37     end;
    38     for i:=1 to n do
    39         for j:=0 to 1 << n-1 do vis[i,j]:=ok(i,j);
    40     for i:=k downto 1 do //i表示当前进行到第i轮
    41         for j:=0 to 1 << n-1 do //n件物品取与不取的状态
    42         begin
    43             for p:=1 to n do if vis[p,j] then f[i,j]:=f[i,j]+max(f[i+1,j],f[i+1,j or (1 << (n-p))]+w[p]) else f[i,j]:=f[i,j]+f[i+1,j];
    44             f[i,j]:=f[i,j]/n;
    45         end;
    46     writeln(f[1,0]:0:6);
    47 end.
  • 相关阅读:
    什么是method swizzling
    手机安全卫士——手机防盗页面
    手机安全卫士——在设置中心 自定义view和自定义属性
    手机安全卫士——主界面的开发
    手机安全卫士——闪屏页相关处理
    Android开发学习——自定义View
    C#开发学习——SqlHelper的应用
    基本的SQL语句
    C#开发学习——常用的正则表达式
    C#开发学习——存储过程
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4480203.html
Copyright © 2011-2022 走看看