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

洛谷P2014 选课(树形DP+0/1背包)

洛谷P2014 选课(树形DP+0/1背包)

题目的关键点是把0看作存在的节点,找到一块由0出发的连通部分(即不能出现断层)

解法一(纯递归)

要计算的是以0为根,包含0的所有子树,节点总数目为m+1的最大权值累加和,设以i为根,包含i的前j棵子树,节点总数目为k的最大权值累加和是dp[i][j][k],只需要考虑前j-1棵子树上选取s门课程,然后在第j棵子树上面选取k-s门课程,状态转移方程为

\[dp[ i ] [j][k]=max(dp[i][j-1][k-s]+dp[v][g[v].size()][s])(s从1到k,v是第j棵子树头节点,v=g[i][j-1]) \]

递归重点是k=1时或者没有子树,此时头节点的权值就是结果

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int> 
#define pb push_back 
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=301,MOD=998244353;
vector<vi> g;
int sco[N];
vector<vector<vi>> dp;
int cal(int i,int j,int k){if(k==0) return 0;if(j==0||k==1) return sco[i];if(dp[i][j][k]!=-1) return dp[i][j][k];int ans=cal(i,j-1,k);int v=g[i][j-1];for(int s=1;s<k;s++){ans=max(ans,cal(i,j-1,k-s)+cal(v,g[v].size(),s));}dp[i][j][k]=ans;return ans;
}void solve(){int n,m;cin>>n>>m;g.clear();g.resize(n+1);m++;dp.resize(n+1);for(int i=1;i<=n;i++){int k,s;cin>>k>>s;g[k].pb(i);sco[i]=s;}for(int i=0;i<=n;i++){dp[i]=vector<vi>(g[i].size()+1,vi(m+1,-1));}cout<<cal(0,g[0].size(),m)<<endl;
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;// cin>>T;while(T--)solve();return 0;
}

时间复杂度为O(n*平均子树大小*m*m)

解法二(树上0/1背包)

使用DFN序,则0节点的DFN序为1,以此类推。在算DFN序的时候把其子树大小算出来,方便后续维护的连续有效结构。

以下节点以表示dfn序节点

从终点算起往回递推,设从节点i到节点n+1里面选择j门课程最大能获取dp[i][j]的学分,那么计算在dp[i+1][j]算出来后只需要考虑是否选入节点i,若选入,则在i+1号节点到n+1之间选择j-1个节点,否则i节点及其子树部分包含的节点都不可以被选入(保持连续)。两种情况取max即可,状态转移方程为

\[dp[i][j]=max(dp[i+1][j-1]+val[i],dp[i+siz[i]][j])|(siz[i]为i的子树大小,包含i) \]

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int> 
#define pb push_back 
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=305,MOD=998244353;//DFN+树形DP
int sco[N],val[N];
int dp[N][N];
int dfncnt;
vi g[N];
int dfn[N],siz[N];//子树大小
int f(int u){//求dfn的递归函数dfn[u]=++dfncnt;int t=dfncnt;siz[t]=1;val[t]=sco[u];for(int v:g[u]){siz[t]+=f(v);}return siz[t];
}void solve(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++){int k,s;cin>>k>>s;g[k].pb(i);sco[i]=s;}f(0);for(int i=n+1;i>=2;i--){for(int j=1;j<=m;j++){dp[i][j]=max(dp[i+1][j-1]+val[i],dp[i+siz[i]][j]);}}cout<<dp[2][m]<<endl;
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;// cin>>T;while(T--)solve();return 0;
}
http://www.jsqmd.com/news/459426/

相关文章:

  • 攻防世界免费题库难度三(2)
  • 茅台app多账户自动预约程序系统源码
  • PCL 中 Point-to-Point / Point-to-Plane / GICP / NDT 的区别与联系
  • 2026年评价高的消防服洗涤设备厂家推荐:酒店洗衣房洗涤设备厂家信誉综合参考 - 行业平台推荐
  • 图图的嗨丝造相-Z-Image-Turbo模型解读:为何选择Z-Image-Turbo作为基座
  • 飞舞大学生成为算法糕手Day 7 | 四数相加Ⅱ、赎金信、三数之和、四数之和
  • 第十八章: Kubernetes - Rancher 控制面板使用
  • 深度学习环境搭建与 Hugging Face 本地模型实战全记录
  • 2026年口碑好的税务问题品牌推荐:税务需求/专业税务公司/成都税务公司项目推荐 - 行业平台推荐
  • 2026年比较好的高品质气压棒厂家推荐:电竞椅子气压棒/自动回位气压棒厂家选购参考汇总 - 行业平台推荐
  • computed 的缓存哲学:如何避免不必要的重复计算?
  • 2026年比较好的追背气弹簧品牌推荐:橱柜气弹簧/支架气弹簧/老板椅气弹簧品牌厂商推荐(更新) - 行业平台推荐
  • Big Data Mining and Analytics 2025|GPT-NAS:结合生成预训练模型的进化式神经架构搜索
  • 第十九章: Kubernetes - Rook Ceph 云原生存储
  • 阿里云 H5 一键登录接入实战:前后端完整实现
  • GE IC693PBS201从站通信模块
  • 第一篇文章
  • Spring AI 第 8 篇 ChatMemory 详解:如何让模型记住你的每一次对话
  • 鸿蒙APP开发经验分享:HarmonyOS Location Kit 端侧与云侧双方案落地指南
  • OpenClaw零基础教程:从一键部署,到7*24小时不间断运行!
  • APN(Access Point Name)详解:从基础原理到实际应用场景
  • 数据资产管理——172页详解数据资产管理深度解读【附全文阅读】
  • 用OpenClaw白嫖世界顶级模型,一个月省了2万块!
  • 嵌入式八股文学习-自学长期更新-2026
  • GitHub Browser-Use 部署踩坑实录:从失败到成功的曲折历程
  • Tower I3C Host Adapter 使用范例 (19)
  • 轻量级AI服务落地实战:Qwen2.5-0.5B-Instruct私有化部署与性能调优指南
  • 8集自然纪录片--Our Planet
  • “养虾”热潮的AB面:大厂抢滩、造富神话和万元账单
  • Java基础面试题之===集合篇