当前位置: 首页 > ds >正文

洛谷 P2473 [SCOI2008] 奖励关


题目传送门


思路

确定算法

  • 首先,一个物品能不能选,还要看有没有选前提物品;
  • 其次,物品种类很少,只有 n ≤ 15 n \leq 15 n15
  • 因此,我们可以确定用 状压 d p dp dp 来求期望。

状态设计

  • 首先,肯定要有记录当前是第 i i i 轮的一维;
  • 其次,由于拿物品还要看已有物品集合,所以要有记录【当前已经拿了物品的集合】的一维;
  • d p i , s dp_{i, s} dpi,s 表示在 【第 1 1 1 i − 1 i - 1 i1 轮】 所拿到的物品集合为 s s s 时,第 i i i k k k 轮在最优情况下,所拿物品分值总和的期望。
    (为什么这么设计到状态转移会说)

状态转移

采用倒推(为什么不用正推等会说):

  1. 若目前状态 s s s 不能拿物品 k k k,那么: d p i , s + = d p i + 1 , s n dp_{i, s} += \frac{dp_{i + 1, s}}{n} dpi,s+=ndpi+1,s
  2. 若目前状态 s s s 可以拿物品 k k k,那么: d p i , s + = m a x ( d p i + 1 , s ∣ ( 1 < < ( k − 1 ) ) + p k , d p i + 1 , s ) n dp_{i, s} += \frac{max(dp_{i + 1, s | (1 << (k - 1))} + p_k, dp_{i + 1, s})}{n} dpi,s+=nmax(dpi+1,s(1<<(k1))+pk,dpi+1,s)分别对应选 k k k 与不选 k k k

问题一:为什么状态这么设计呢?

  1. 为了适应倒推的转移方程;
  2. 如果状态设计为【 d p i , s dp_{i, s} dpi,s 表示到第 i i i拿完后,且状态为 s s s 时,已有的分数的期望】(适应正推),就会影响后面物品的选择。因为有前驱物品集合的限制,这样 d p dp dp 就会有后效性,导致不正确。

问题二:为什么采用倒推呢 ?

  • 同样也是因为正推会有后效性。

边界条件

  • 对于 ∀ s ∈ [ 0 , 2 n − 1 ] \forall s \in [0, 2^n - 1] s[0,2n1] d p n + 1 , s dp_{n + 1, s} dpn+1,s 均为 0 0 0
  • 含义就是:在 1 1 1 n n n 轮选完的状态 s s s 下,已经结束了,不能再选了,因此期望为 0 0 0

答案

  • 就是 d p 1 , 0 dp_{1, 0} dp1,0,含义就是:还没有开始时,一个物品都没选的状态,所能得到的期望分。

复杂度

  • 空间: O ( k × n ) O(k \times n) O(k×n)
  • 时间: O ( k × n × 2 n ) O(k \times n \times 2^n) O(k×n×2n)

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 1e2 + 7;
const int maxs = (1 << 15) + 7;int n, m;
struct Prize {int p, s;} a[maxn];
double dp[maxn][maxs];
int main () {scanf("%d%d", &n, &m);for (int i = 1, x; i <= m; ++i) {scanf("%d", &a[i].p);while (1) {scanf("%d", &x);if (!x) break;a[i].s |= 1 << (x - 1);}}for (int i = n; i >= 1; --i) {for (int s = 0; s < (1 << m); ++s) {for (int k = 1; k <= m; ++k) {if ((s & a[k].s) != a[k].s) dp[i][s] += dp[i + 1][s];else dp[i][s] += max(dp[i + 1][s], dp[i + 1][s | (1 << (k - 1))] + a[k].p);}dp[i][s] /= m;}}printf("%.6lf\n", dp[1][0]);return 0;
}

反思

  1. 依旧只想出了状态,没对转移方程;
  2. 发现对这种 最优值期望 的转移方程我总会写成 最优值 的转移方程,并没有很好地理解期望的含义及计算方法;
  3. 运用 倒推 的意识少;
  4. 那种【前面选择】影响【后面选择】的 d p dp dp 最好用倒推,因为先考虑后面,就不用管前面的影响了。
http://www.xdnf.cn/news/3989.html

相关文章:

  • TS 类型别名
  • ES6入门---第三单元 模块一:类、继承
  • 【操作系统】死锁
  • [pdf,epub]292页《分析模式》漫谈合集01-59提供下载
  • 【C语言入门级教学】VS使用调试技巧1
  • 算法笔记.求约数
  • 303.整数拆分
  • Seata TCC 实战笔记:从零搭建分布式事务 Demo (含源码)
  • Linux的时间同步服务器
  • 【LLM】deepseek R1之GRPO训练笔记(持续更新)
  • 【TF-BERT】基于张量的融合BERT多模态情感分析
  • 代码随想录算法训练营Day44
  • PyTorch_张量索引操作
  • Spring Cloud Gateway路由+断言+过滤
  • Flask + SQLite 简单案例
  • 位置权限关掉还能看到IP属地吗?全面解析定位与IP的关系
  • 腾讯云服务器技术全景解析:从基础架构到行业赋能​
  • React-router v7 第七章(导航)
  • 如何使用VSCode编写C、C++和Python程序
  • ES类迁移方法
  • 【翻译、转载】MCP 提示 (Prompts)
  • Kubernetes 安装 minikube
  • 计算机图形学编程(使用OpenGL和C++)(第2版) 01.环境搭建
  • Python的ArcPy基于Excel表格对大量遥感影像批量重分类
  • 第8章 Python 其他数据类型概述
  • LeetCode 1007. 行相等的最少多米诺旋转 题解
  • ZArchiver正版:高效文件管理,完美解压体验
  • 二、大模型原理:图文解析Transformer原理与代码
  • 第十章.XML
  • Android第三次面试总结之activity和线程池篇(补充)