树形背包 / 树形DP(牛客 - 蓝魔法师)
一般的树形背包问题,往往与以下模板异曲同工。复杂度为
void dfs(int u) { sz[u] = 1; for(auto v:G[u]) { dfs(v); sz[u]+=sz[v]; for(int j=sz[u]; j>=1; --j) //滚动背包,枚举自己的所有状态 for(int k=0; k<=j; ++k) //枚举儿子的所有状态 dp[u][j] = max(dp[u][j], dp[u][k] + dp[v][j-k]); //选或不选 } }
——上下界优化——
我们可以舍弃四个无效的状态转移:(设m为背包上限)
- j > m 的状态是无用的,因为答案不需要
- j > 当前背包容量的状态是无用的
- k至少要从 j - size[ u ] 开始 (size[ u ]是当前总节点数,尚在更新中)
- k > size[ v ]的状态是无用的
通过这四个优化,可以将时间复杂度缩短至
void dfs(int u) { sz[u] = 1; for(auto v:G[u]) { dfs(v); for(int j=min(m,sz[u]+sz[v]); j>=1; --j) //滚动背包,枚举自己的所有状态 for(int k=max(0,j-sz[u]); k<=min(j,sz[v]); ++k) //(对k加了上下界限制)枚举儿子的所有状态 dp[u][j] = max(dp[u][j], dp[u][k] + dp[v][j-k]); //选或不选 sz[u]+=sz[v]; //随后再加上 } }
给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一条边在一个方案中被删除,而在另一个方案中未被删除,答案对998244353取模。(1<=n, k<=2000)
设
对于动态规划状态设计,网上的其他题解一般是:设
我个人想到的状态设计:
转移方程:
断边:
不断边:
void dfs(int x,int f) { sz[x]=1; dp[x][1]=1; for(int i:G[x]) { if(i==f) continue; dfs(i,x); for(int j=min(k,sz[x]+sz[i]);j>0;--j) //滚动数组 { (dp[x][j]*=ans[i])%=mod;//断边(因为是乘法,注意要先于不断边) for(int s=max(1,j-sz[x]);s<=min(j,sz[i]);++s) { (dp[x][j]+=dp[x][j-s]*dp[i][s])%=mod; //不断边(此时显然不会对dp[x][1]有贡献) } } sz[x]+=sz[i]; } for(int i=1;i<=k;++i) (ans[x]+=dp[x][i])%=mod; }
其他做法
考虑到包含根节点在内的连通块,一定是由原树删去若干个子树得到,而这些子树又是DFS序上的连续区间,因此可以设
当然,为了保证复杂度,仍需采取上下界优化。
int up,sz[maxn],r[maxn]; int dt[maxn]; //深度 void dfs(int x,int f,int d) { int dfn=++up; //左端点的时间戳 dt[dfn]=d; sz[x]=1; for(int i:G[x]) { if(i==f) continue; dfs(i,x,d+1); sz[x]+=sz[i]; } r[dfn]=up; //右时间戳 dp[dfn][1]=1; //开始时,树体仅含本节点 for(int i=dfn;i<up;++i) //扫一遍以u为根的子树。注意是小于号 { for(int j=max(1,dt[i+1]-d);j<=min(k,i-dfn+1);++j) //当前包含根的块的大小至少为当前点到根的距离 { (dp[i+1][j+1]+=dp[i][j])%=mod; //选下一个节点 (dp[r[i+1]][j]+=dp[i][j]*ans[i+1])%=mod; //不选下一个节点,相当于切去这棵子树 dp[i][j]=0; //作完贡献后,顺便置零 } } for(int i=0;i<=min(k,sz[x]);++i) { (ans[dfn]+=dp[up][i])%=mod; dp[up][i]=0; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具