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

    题目链接:P2473 [SCOI2008]奖励关

    题意:
    有n个宝物 每次等概率抛出其中之一
    一共抛出k次
    每个宝物有一个价值 和一个前提集合
    只有集齐了集合中的所有宝物 才可以领取这个宝物
    范围:1 <= k <= 100, 1 <= n <= 15,分值为[-106,106]内的整数
     
    这个范围长得很dp呀
    这个n长得很状压啊
     
    最初想法:
    对于负价值宝物
    我们计算它本身的贡献与它带来的期望贡献
    来判定是否可取
    对每一个宝物记录它自己的贡献
    最后求和
     
    正解:逆向状压
    2 ^ 15 = 32768
    由于为什么不是正向 是为了避开在第i轮状态S不合法的情况
    这就是本题的思维瓶颈
    刚刚纠结的负数问题 其实说白了就是取决于它后面的状态
    所以逆推又避开了这个坑
    显然二维dp 一维控制轮数 一维控制状态
    三重循环 外面两重分别是这两维
    第三重枚举第1~n个物品
    若状态j中有物品k需要的所有物品
    那么它的价值就是取或不取的最大值
    max(f[i + 1][j], f[i + 1][j | (1 << k)] + w[k])
    没有就只能不取
    f[i + 1][j]
    由于求的是期望
    每个状态转移完除以n
    附上代码:
     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstdlib>
     4 #include <cmath>
     5 using namespace std;
     6 const int N = 105;
     7 const int M = 16;
     8 int inc[M + 5];
     9 double w[M + 5];
    10 int n, m;
    11 double f[N][1 << M];
    12  
    13 int main(){
    14     scanf("%d%d", &m, &n);
    15     for(int i = 1, x; i <= n; i++){
    16         scanf("%lf", &w[i]);
    17         while(scanf("%d", &x) && x)
    18             inc[i] |= (1 << x);
    19     }
    20     int lb;
    21     for(int i = m; i >= 1; i--)
    22     for(int j = 0; j < (1 << (n + 1)); j++){
    23         for(int k = 1; k <= n; k++){
    24             if((j & inc[k]) == inc[k]){
    25                 f[i][j] += max(f[i + 1][j], f[i + 1][j | (1 << k)] + w[k]);
    26             }
    27             else f[i][j] += f[i + 1][j];
    28         }
    29         f[i][j] /= (1.0 * n);
    30     }
    31     printf("%.6lf", f[1][0]);
    32     return 0;    
    33 }
    View Code
  • 相关阅读:
    Arrays类和Timer类(定时调度)
    Centos6.3下Ganglia3.6.0安装配置
    【编程之美挑战赛第一场】树
    ORACLE物化视图具体解释
    让算法会说话之冒泡排序
    VS2008帮助"更新正在进行中"解决办法
    #问题
    sql server 2008 评估期已过期解决办法
    eclipse定义枚举类型错误
    C# 生产者和消费者问题使用Monitor同步
  • 原文地址:https://www.cnblogs.com/hjmmm/p/9426673.html
Copyright © 2011-2022 走看看