zoukankan      html  css  js  c++  java
  • 奖励关[SCOI2008]

      题目链接:https://www.luogu.org/problemnew/show/P2473

     

    题目描述

    你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出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
    输出样例#1: 
    1.500000
    输入样例#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
    
    输出样例#2: 
    10.023470

    说明

    1 <= k <= 100, 1 <= n <= 15,分值为[-106,106]内的整数。

     题解:

      状压+期望dp

      考虑对于一个状态s,若玩具i能被选(即(prei&s) == prei),则dpnow,s += max(dpnow+1,s,dpnow+1,s|(1<<(i-1))+ci)*1/n;否则dpnow,s += dfsnow+1,s*1/n 。

      转移方程不太好想,所以我用了记忆化搜索。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define LL long long
     7 #define RI register int
     8 using namespace std;
     9 const int INF = 0x7ffffff ;
    10 const int N = 15 + 2 ;
    11 const int K = 100 + 10 ;
    12 
    13 inline int read() {
    14     int k = 0 , f = 1 ; char c = getchar() ;
    15     for( ; !isdigit(c) ; c = getchar())
    16       if(c == '-') f = -1 ;
    17     for( ; isdigit(c) ; c = getchar())
    18       k = k*10 + c-'0' ;
    19     return k*f ;
    20 }
    21 int k, n ;  double dp[K][1<<N] ; int bit[N], c[N], pre[N] ;
    22 
    23 double dfs(int now,int s) {
    24     if(dp[now][s] != -INF) return dp[now][s] ;
    25     dp[now][s] = 0 ;
    26     if(now == k) return dp[now][s] ;
    27     for(int i=1;i<=n;i++) {
    28 //        printf("pre[i]&s:%d pre[i]:%d
    ",pre[i]&s,pre[i]) ;  // 之前下面一行没加括号时的输出调试
    29         if((pre[i]&s) == pre[i]) {  // 这个括号很关键...因为位运算的优先级还不如等号qwq 
    30             dp[now][s] += max(dfs(now+1,s),dfs(now+1,s|bit[i])+(double)c[i]) ;
    31         }
    32         else dp[now][s] += dfs(now+1,s) ;
    33     }
    34     dp[now][s] /= (double)n ;
    35     return dp[now][s] ;
    36 }
    37 
    38 int main() {
    39     k = read(), n = read() ;
    40     bit[1] = 1 ;
    41     for(int i=2;i<=(n+1);i++) bit[i] = bit[i-1]<<1 ;  // 记录每个宝物代表的二进制数
    42     memset(pre,0,sizeof(pre)) ;
    43     for(int i=1;i<=n;i++) {
    44         c[i] = read() ;
    45         while(1) {
    46             int x = read() ; if(!x) break ;
    47             pre[i] += bit[x]  ;
    48         }
    49     }
    50     for(int i=0;i<=k;i++) {
    51         for(int s=0;s<bit[n+1];s++) dp[i][s] = -INF ;
    52     }
    53     dfs(0,0) ; printf("%.6lf",dp[0][0]) ;
    54     return 0 ;
    55 }
  • 相关阅读:
    A
    B
    C
    I
    公共最大字串长度
    docker run 的背后的故事(zz)
    python之多并发socket(zz)
    Python垃圾回收机制:gc模块(zz)
    我要做的git的分享(zz)
    SpringMVC框架入门配置 IDEA下搭建Maven项目(zz)
  • 原文地址:https://www.cnblogs.com/zub23333/p/8637268.html
Copyright © 2011-2022 走看看