#树形依赖背包,点分治#BZOJ 4182 Shopping
题目
给定一棵大小为 \(n\) 的树,每个点代表一种物品,其具有体积、价值和数量的属性,
现在选择一个连通块,使得里面所有点都被选中且体积不超过 \(m\),问最大价值。
\(n\leq 500,m\leq 4000\)
分析
树形背包比较难维护,考虑用dfs序拍平到序列上,并且多重背包直接二进制拆分。
设 \(dp[i][j]\) 表示dfs序为 \(i\),且选择体积为 \(j\) 时能获得的最大价值。
如果不选这个点,那么 \(dp[i][j]=dp[rfn[i]][j]\),\(rfn\) 表示这个点的下一个兄弟的dfs序
如果选择这个点,那么 \(dp[i][j]=\max\{dp[i+1][j-w]+c\}\)
但有一个问题就是这样会变成01背包,考虑先用上式更新一次(强制必选一个),再用 \(dp[i][j-w]\) 更新。
就是在二进制拆分时先拆一个再正常拆,发现这样根节点强制必选,那么跑点分治,所有连通块都能被以当前根节点的情况所表示。
可以通过二进制拆分的个数来决定点的大小求带权重心,这样时间复杂度为 \(O(Tnm\log n\log m)\)
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=511; struct node{int y,next;}e[N<<1]; struct rec{int w,c;}a[N<<3];
int siz[N],big[N],as[N],L[N],R[N],w[N],c[N],ans,root,tot,v[N],dfn[N],nfd[N],rfn[N],et=1,n,m,k,dp[N][N<<3];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void Max(int &x,int y){x=x>y?x:y;}
void dfs(int x,int fa){
siz[x]=R[x]-L[x]+1,big[x]=0;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y]){
dfs(e[i].y,x),siz[x]+=siz[e[i].y];
Max(big[x],siz[e[i].y]);
}
Max(big[x],big[0]-siz[x]);
if (big[x]<=big[root]) root=x;
}
void calc(int x,int fa){
dfn[x]=++tot,nfd[tot]=x;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y])
calc(e[i].y,x);
rfn[x]=tot+1;
}
void Dp(int x){
v[x]=1,tot=0,calc(x,0);
for (int i=0;i<=k;++i) dp[tot+1][i]=0;
for (int i=tot;i;--i){
int x=nfd[i];
for (int j=0;j<=k;++j) dp[i][j]=dp[rfn[x]][j];
for (int j=k;j>=w[x];--j)
Max(dp[i][j],dp[i+1][j-w[x]]+c[x]);
for (int o=R[x];o>L[x];--o)
for (int j=k;j>=a[o].w;--j)
Max(dp[i][j],dp[i][j-a[o].w]+a[o].c);
}
Max(ans,dp[1][k]);
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]){
big[0]=siz[e[i].y];
dfs(e[i].y,root=0),Dp(root);
}
}
int main(){
for (int T=iut();T;--T){
n=iut(),k=iut(),ans=m=0,et=1;
for (int i=1;i<=n;++i) c[i]=iut();
for (int i=1;i<=n;++i) w[i]=iut();
for (int i=1;i<=n;++i){
int x=iut(); L[i]=R[i-1]+1;
a[++m]=(rec){w[i],c[i]},--x;
for (int t=1;x>=t;x-=t,t<<=1)
a[++m]=(rec){w[i]*t,c[i]*t};
if (x) a[++m]=(rec){w[i]*x,c[i]*x};
R[i]=m;
}
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
big[0]=m,dfs(1,root=0),Dp(root);
print(ans),putchar(10);
for (int i=1;i<=n;++i) v[i]=as[i]=0;
}
return 0;
}
#树形依赖背包,点分治#BZOJ 4182 Shopping的更多相关文章
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
- BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...
- bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)
菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...
- Gym - 100502G Outing (强连通缩点+树形依赖背包)
题目链接 问题:有n个人,最多选k个,如果选了某个人就必须选他指定的另一个人,问最多能选多少个人. 将每个人所指定的人向他连一条单向边,则每一个点都有唯一的前驱,形成的图是个基环树森林,在同一个强连通 ...
- RNQOJ [stupid]愚蠢的矿工(树形依赖背包)
题意 题目链接 Sol 树形依赖背包板子题 树形依赖背包大概就是说:对于一个点,只有选了它的父亲才能选自身 把dfs序建出来,倒过来考虑 设\(f[i][j]\)表示从第\(i\)个节点往后背包体积为 ...
- 【bzoj2427】【软件安装】tarjan缩点+树形依赖背包
(上不了p站我要死了,侵权度娘背锅) Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上, ...
- 【LuoguP1273有线电视网】树形依赖背包
参考论文http://wenku.baidu.com/view/8ab3daef5ef7ba0d4a733b25.html 参考一篇写的很好的博文http://www.cnblogs.com/GXZC ...
- BZOJ 4182 Shopping (点分治+树上多重背包)
题目大意:给你一颗树,你有$m$元钱,每个节点都有一种物品,价值为$w$,代价为$c$,有$d$个,如果在$u$和$v$两个城市都购买了至少一个物品,那么$u,v$路径上每个节点也都必须买至少一个物品 ...
- AcWing 286. 选课 (树形依赖分组背包)打卡
有依赖的背包 首先依赖的概念,就是一个东西依附与一个东西之上,我们想买附品的话必须要把主品先买下来,这个可以先做下这道题 https://www.cnblogs.com/Lis-/p/11047466 ...
- 【HDU 4276】The Ghost Blows Light(树形DP,依赖背包)
The Ghost Blows Light Problem Description My name is Hu Bayi, robing an ancient tomb in Tibet. The t ...
随机推荐
- 详解SSL证书系列(2)SSL证书对网站的好处
在如今谷歌.百度等互联网巨头强制性要求网站 HTTPS 化的情况下, 网站部署 SSL 证书已然成为互联网的发展趋势,我们也知道了 SSL证书可以防止网络安全威胁.那么除此外为网站部署 SSL 证书还 ...
- 【LeetCode贪心#04】跳跃游戏I + II
跳跃游戏 力扣题目链接(opens new window) 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示 ...
- 【LeetCode二叉树#10】从中序与后序(或者前序)遍历序列构造二叉树(首次构造二叉树)
从中序与后序遍历序列构造二叉树 力扣题目链接(opens new window) 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorde ...
- 【LeetCode哈希表#4】梦开始的地方:两数之和(map),以及关于容器map的一些代码技巧
两数之和 力扣题目链接(opens new window) 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种 ...
- 【Azure 云服务】指标哪去了?在执行 Swap (交换生产部署和Staging部署) 操作后看不见云服务的旧指标
问题描述 打开云服务(Cloud Service)的Metrics页面,发现过去了指标不见了? 以虚点构成无数据的图表. 问题解答 查看云服务的活动日志(Activity Logs),发现最近执行的操 ...
- linux 命令行使用codeql
目录 CodeQL 概述 安装 直接使用在线查询(lgtm) vscode使用codeql 下载 库文件 测试 linux控制台运行 下载 安装 创建数据库 编写QL查询数据库 简单解释 CodeQL ...
- 影刀rpa第一个学习项目开发所得
1.我要在某个位置新增一条指令,但是可能没有选择好的原因,这条指令被添加到指令的最后面了,我的指令行数有几十行,然后我就要把这条指令拖动到上一屏我指定的位置上,但当我拖动指令到了当前屏最上方时,发现编 ...
- C#与C互操作
C#给C++传递char**(转载) extern "C" _declspec(dllexport)void GetResult(char* a,char** pBuf) { sp ...
- 1. zookeeper简介与应用场景
1.1 zookeeper介绍 zookeeper是一个高可用的分布式管理与协调框架,基于ZAB算法(原子消息广播协议)的实现. 能够很好保证分布式环境中数据的一致性.正是基于这样的特性,使得zo ...
- 我的闲鱼Python爬虫接单总结和经验,最高600元一单
最近,我在闲鱼上利用 Python 爬虫技术接了一些任务,想必你一定好奇,通过这样的方式,到底能不能挣钱,能挣多少钱?今天我就来分享一下我的经验和总结. 一.接单经历 之前 Vue 的作者尤大在微博上 ...