zoukankan      html  css  js  c++  java
  • $Luogu$ $P2014$ 选课

    链接

    背景

    (Luogu) (P2014)

    题意

    给定 (n) 个物品的依赖物品 (k_i)(k_i=0) 表示无依赖物品)及权值 (val_i) ,求选出 (m) 件物品的最大权值和。

    解法

    背包类树形 (dp) 模板。
    考虑把所有依赖关系画在一张图上,显然是一个森林。不妨把每棵树的根都设定一个 (0) 号物品作为依赖物品,则整张图就变成了一棵以 (0) 为根节点的树了。
    按照套路,设 (f_{x,t}) 表示以 (x) 节点为根的子树里选出了 (t) 件物品的最大权值和。假设当前节点 (x) 的儿子为 (y_1,y_2,y_3,cdots cdots,y_p)(p) 个,则转移方程就是 (f_{x,t}=max_limits{ sum_limits{i in [1,p]} t_i=t-1} { sum_limits{i in [1,p]} f_{y_i,t_i} }+val_x)
    考虑变形。这个转移本质上就是从 (p) 组每组都有 (t-1) 个物品的物品集合里每组选出一个物品,一共选出 (t-1) 个。因此采用分组背包的转移即可。
    注意 (x=0) 时并不需要选根节点(即此时可以选 (t) 个物品),于是先不做根节点 (dp) 值的更新,子树都更新完之后再根据 (x) 是否为 (0)(f_{x,t-1}) 转移到 (f_x) 即可。
    另外,由于这是一个分组背包,每件物品只能用一次,所以循环体积的时候要倒序枚举。又因为有体积为 (0) 的物品,所以对于组内物品的枚举也需要倒序。

    细节

    对于给定依赖关系的处理,由于 (k_i=0) 表示无依赖物品,而我们也正好设定一个 (0) 号物品作为依赖物品,于是它的处理与其他的处理没有任何区别,直接在被依赖物品的儿子里加入依赖它的物品即可。

    代码

    $View$ $Code$ ```cpp #include using namespace std; inline int read() { int ret=0,f=1; char ch=getchar(); while('9' sons[305]; void dp(int x) { f[x][0]=0; int siz=sons[x].size(); for(register int i=0;i
  • 相关阅读:
    bit byte哪些事
    各种字符集和编码详解
    常用工具大全
    表单提交的3种方式,http post的contentType
    主动发电
    Hibernate与 MyBatis的比较
    storm简介
    2013年十大免费云空间排行榜-给开发者建站用的免费云主机
    中国著名讲师全录
    iptables只允许指定ip地址访问指定端口
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11837616.html
Copyright © 2011-2022 走看看