【学习笔记】【题解】树形依赖 DP 选做
地址:https://www.cnblogs.com/FReQuenter5156/p/shuxingyilaidp.html/
简介
这类背包本质上是分组背包问题。
将一个节点的每一棵子树看作一组,进行分组背包。所谓分组背包,即在选择物品的时候,一开始将物品分为好几组,在选择时,可以从每一组中至多选择一件物品,问如何获得最大的价值,所以我们每次可以枚举这个组数,用 \(i\) 表示第几组,用 \(j\) 表示体积,用 \(k\) 来表示选择的物品,伪代码如下:
for (int i=0到组数)
for (int j=max_v到0)
for (int k=此组所有物品)
f[j]=max(f[j],f[j-v[k]]+w[k])
注意循环顺序。这个和 01 背包的道理类似。
例题
[CTSC1997] 选课
题面
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有 \(N\) 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程 a 是课程 b 的先修课即只有学完了课程 a,才能学习课程 b)。一个学生要从这些课程里选择 \(M\) 门课程学习,问他能获得的最大学分是多少?
题解
定义
\(f_{i,j}\) 表示当前第 \(i\) 个点的子树内选 \(j\) 个点(不包括自己)的最大学分。
转移
直接套板子。初值在输入时已经设置好了,DP 中只要比大小。具体参考代码。
代码
#include<bits/stdc++.h>
#define MAXN 305
using namespace std;
int n,m,k[MAXN],s[MAXN],sz[MAXN],f[MAXN][MAXN];
vector<int> gv[MAXN];
void dfs(int now,int father){
sz[now]=1;
for(auto nx:gv[now]){
if(nx!=father) dfs(nx,now),sz[now]+=sz[nx];
}
}
void dp(int now,int father){
int sum=0;
for(auto nx:gv[now]){
if(nx==father) continue;
sum+=sz[nx];
dp(nx,now);
for(int j=sum;j>=0;j--){
for(int k=0;k<sz[nx];k++){
if(j-k>=1){
f[now][j]=max(f[now][j],f[now][j-k-1]+f[nx][k]);
}
}
}
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>k[i]>>s[i];
gv[k[i]].push_back(i);
f[i][0]=s[i];
}
dfs(0,0);
dp(0,0);
cout<<f[0][m];
}
有线电视网
题面
某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。
从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。
现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。
写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。
题解
定义
\(f_{i,j}\) 表示到第 \(i\) 个点供应 \(j\) 个用户的最大收益。最后求答案的时候枚举下 \(f_{1,i}\geq 0\) 的最大 \(i\)。注意初值赋 -INF。
转移
也是套板子。直接看代码应该就能理解。
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define MAXN 3005
using namespace std;
vector<pair<int,int>> gv[MAXN];
int n,m,f[MAXN][MAXN],v[MAXN];
int dp(int now){
if(now>=n-m+1){
f[now][1]=v[now];
return 1;
}
int sum=0;
for(auto nx:gv[now]){
int tmp=dp(nx.fi);
sum+=tmp;
for(int j=sum;j>=1;j--){
for(int k=1;k<=tmp;k++){
if(j-k>=0) f[now][j]=max(f[now][j],f[now][j-k]+f[nx.fi][k]-nx.se);
}
}
}
return sum;
}
signed main(){
memset(f,-0x3f,sizeof(f));
cin>>n>>m;
for(int i=1;i<=n-m;i++){
int k;
cin>>k;
for(int j=1;j<=k;j++){
int a,c;
cin>>a>>c;
gv[i].push_back({a,c});
}
}
for(int i=n-m+1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++) f[i][0]=0;
int maxn=0;
dp(1);
for(int i=0;i<=m;i++) if(f[1][i]>=0) maxn=i;
cout<<maxn;
}
重建道路
题面
一场可怕的地震后,人们用 \(N\) 个牲口棚(编号 \(1\sim N\))重建了农夫 John 的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。
John 想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有 \(P\) 个牲口棚的子树和剩余的牲口棚分离,John 想知道这些道路的最小数目。
题解
定义
\(f_{i,j}\) 表示当前第 \(i\) 个点为根的子树保留 \(j\) 个点(包括自己)删去的最小的边数。答案需要枚举所有的子树。
转移
其实也差不多。可以直接看代码。注意初始值 \(f_{i,1}\) 为每个点的出度。这题相对来说比较细节。如方程中的 -1,和自己的“父亲”的连边不能拆。
代码
#include<bits/stdc++.h>
using namespace std;
vector<int> gv[155];
int n,p,ans=0x3f3f3f3f,f[155][155],sz[155],od[155];
bool ir[155];
void dp(int now){
sz[now]=1;
if(!od[now]) return f[now][1]=0,void();
for(auto nx:gv[now]){
dp(nx);
sz[now]+=sz[nx];
for(int j=sz[now];j>=0;j--) for(int k=1;k<j;k++) f[now][j]=min(f[now][j],f[now][j-k]+f[nx][k]-1);
}
}
signed main(){
cin>>n>>p;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
gv[x].push_back(y),od[x]++,ir[y]=true;
}
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) f[i][1]=od[i];
int root=0;
for(int i=1;i<=n;i++) if(!ir[i]) root=i;
dp(root);
for(int i=1;i<=n;i++){
if(i==root) ans=min(ans,f[i][p]);
else ans=min(ans,f[i][p]+1);
}
cout<<ans;
return 0;
}
拓展
[JSOI2016]最佳团体
题面
JSOI 信息学代表队一共有 \(N\) 名候选人,这些候选人从 \(1\) 到 \(N\) 编号。方便起见,JYY 的编号是 \(0\) 号。每个候选人都由一位编号比他小的候选人\(R_i\) 推荐。如果 \(R_i = 0\)?,则说明这个候选人是 JYY 自己看上的。
为了保证团队的和谐,JYY 需要保证,如果招募了候选人 \(i\),那么候选人 \(R_i\) 也一定需要在团队中。当然了,JYY 自己总是在团队里的。每一个候选人都有一个战斗值 \(P_i\) ,也有一个招募费用 \(S_i\) 。JYY 希望招募 \(K\) 个候选人(JYY 自己不算),组成一个性价比最高的团队。也就是,这 \(K\) 个被 JYY 选择的候选人的总战斗值与总招募费用的比值最大。
题解
简单说一下。比值类似于 最优比例生成树,可以使用分数规划,然后就可以去套板子了。
没来得及实现,可以参考洛谷题解。
【学习笔记】【题解】树形依赖 DP 选做的更多相关文章
- 【学习笔记】动态规划—各种 DP 优化
[学习笔记]动态规划-各种 DP 优化 [大前言] 个人认为贪心,\(dp\) 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT).这篇文章也是花了我差不多一个月时间才全部完成 ...
- .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]
原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...
- .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]
原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- .NET CORE学习笔记系列(2)——依赖注入【3】依赖注入模式
原文:https://www.cnblogs.com/artech/p/net-core-di-03.html IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流 ...
- .NET CORE学习笔记系列(2)——依赖注入【2】基于IoC的设计模式
原文:https://www.cnblogs.com/artech/p/net-core-di-02.html 正如我们在<控制反转>提到过的,很多人将IoC理解为一种“面向对象的设计模式 ...
- 「学习笔记」wqs二分/dp凸优化
[学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...
- .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...
- .NET CORE学习笔记系列(2)——依赖注入【1】控制反转IOC
原文:https://www.cnblogs.com/artech/p/net-core-di-01.html 一.流程控制的反转 IoC的全名Inverse of Control,翻译成中文就是“控 ...
- 汇编入门学习笔记 (七)—— dp,div,dup
疯狂的暑假学习之 汇编入门学习笔记 (七)-- dp.div.dup 參考: <汇编语言> 王爽 第8章 1. bx.si.di.和 bp 8086CPU仅仅有4个寄存器能够用 &qu ...
随机推荐
- mysql 8.0.30 忘记密码登录mysql:
mysql 8.0.30 忘记密码登录mysql: cmd(使用管理员运行)-切换到mysql的bin目录下:一.输入命令:net stop mysql 停止服务: 二.输入命令:mysqld --c ...
- Net异步委托-泛型委托Action<T>与Func<T,TResult>及 异步调用AsyncCallback
1.相同点 Func<ReqMode,ResultModel> 与 Action<ReqMode> 1).都是Net3.5 之后内置的委托方法,作用几乎一致 2).都支持lam ...
- mfc edit只允许输入数字
1.给EDIT控件添加 EN_CHANGE 事件 2.事件中的代码如下: 1 CString strEditVidoe; 2 GetDlgItem( iId )->GetWindowText( ...
- Spring--注解开发+依赖注入
自动装配 数据层: 业务层: 自动装配: 结果: 若是将自动装配的注解放在set函数处: 结果: 结果相同,若是将set方法去掉的话: 结果: 这样的话,set方法也得到解放了耶! 以上都是按照类型装 ...
- 对于利用Java Script实现的判断的基础浅层总结
各种判断,请收好啦! 判断输入框中的数据是否为整数: 点击删除按钮,出现判断是否删除的弹窗 在button里面加上这样一句话就能够实现删除判断弹窗啦!
- Echarts中slider滑块调整样式
今天遇到了一个问题,记录一下. 效果图. 原型图 一个页面中,引入了echarts的柱状图来动态显示数据,由于柱状图太高,echarts没有自动生成的滚动条,所以就用slider滑块手写了一个,但是效 ...
- Why WebRTC|“浅入深出”的工作原理详解
前言 近几年实时音视频通信应用呈现出了大爆发的趋势.在这些实时通信技术的背后,有一项不得不提的技术--WebRTC. 今年 1 月,WebRTC 被 W3C 和 IETF 发布为正式标准.据调研机构 ...
- 基于 Agora SDK 实现 Windows 端的一对一视频通话(基于3.6.2版本)
前提条件 Microsoft Visual Studio 2019 或以上版本 支持 Windows 7 或以上版本的 Windows 设备 有效的 Agora 账户(免费注册) 注:如果你的网络环境 ...
- EF Code 如何应对高并发
1.高并发的情况,时常会发生数据不稳定的情况 在看本节内容之前,请先看上一章SqlServer 高并发的情况下,如何利用锁保证数据的稳定性 本节内容,也是具体讨论如何在EF中实现这些操作 2.场景模拟 ...
- Salesforce LWC学习(三十三) lightning-datatable 翻页bug处理
本来lightning-datatable这种标签,基本上任何的项目都会用到而且很精通,所以当时感觉没有太大的单独一篇写的必要,在Salesforce LWC学习(三十) lwc superbadge ...