【题解】[SDOI/SXOI2022] 小 N 的独立集(dp of dp)
题目分析:
就借助这个题稍微说一下 套 。
对于 套 其解决的问题是:若给定某一具体情况则答案十分好求,现要求对于所有的情况的答案进行统计。
这类问题我们一般称解决这个具体情况的 为内层 ,而对于所有情况进行统计的 为外层 。
一般的解决方法是:将内层 的状态直接扔到外层 的下标上,然后再按需要加入一些新的下标,也就是说假设内层 的状态为 ,那么我们的外层 则至少应为 ,表示 时统计的答案,转移时即按照内层 的转移方式对于下标进行转移。
下面就以这个题为例看看 套 的具体应用。
看到这个题的第一眼就可以知道,若给定权值,则树上的最大权独立集是很好求的,就是直接设 表示以 为根的子树, 节点不选/选的最大权独立集是多少。
考虑 的值并不大,所以可以使用 套 ,即设 表示以 为根的子树 的方案数,那么转移就是显然的:(设 为 的儿子节点)
根据树上背包的复杂度分析,这样直接做的复杂度为 。
对于 套 常见优化就是压缩状态或者优化转移。
我们其实可以发现一条性质: 不会比 大很多,虽然 可能比 大很多。
也就是说 不大,稍微分析一下就可以发现满足:
因为 是在子树上按最优的方式转移的,即使 也是最优的方式转移也只会多 的贡献。
(注意这一行状态已经重新设计了)所以我们就可以将内层 状态重新设计为: 表示 节点不强制/强制不选的答案, 表示 的方案数。
转移也是显然的:
这样的话复杂度就优化为了
需要注意一点就是 中 可以为 ,因为显然不强制不选的最优答案可以为不选。
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e3+5;
const int K = 7;
const int MOD = 1e9+7;
struct edge{
int nxt,to;
edge(){}
edge(int _nxt,int _to){
nxt = _nxt,to = _to;
}
}e[2 * N];
int n,k,cnt,head[N],sz[N],g[N][N*K][K],f[N*K][K],ans[N*K];
//g[now][i][j] 表示 now 为根的子树,now 随意选不选权值为 i + j,now 强制不选权值为 i 的方案数
void add_edge(int from,int to){
e[++cnt] = edge(head[from],to);
head[from] = cnt;
}
void dfs(int now,int fath){
sz[now] = 1;
for(int i=1; i<=k; i++) g[now][0][i] = 1;
for(int i=head[now]; i;i=e[i].nxt){
int to = e[i].to;
if(to == fath) continue;
dfs(to,now);memset(f,0,sizeof(f));
for(int a=0; a<=sz[now]*k; a++){
for(int b=0; b<=k; b++){
if(g[now][a][b] == 0) continue;
for(int c=0; c<=sz[to]*k; c++){
for(int d=0; d<=k; d++){
f[a+c+d][max(a+b+c,a+c+d)-(a+c+d)] = (f[a+c+d][max(a+b+c,a+c+d)-(a+c+d)] + g[now][a][b] * g[to][c][d])%MOD;
//其实转移就是正常的转移
}
}
}
}
memcpy(g[now],f,sizeof(f));
sz[now] += sz[to];
}
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%lld%lld",&n,&k);
for(int i=1; i<n; i++){
int from,to;scanf("%lld%lld",&from,&to);
add_edge(from,to);add_edge(to,from);
}
dfs(1,0);
for(int i=1; i<=n*k; i++){
for(int j=0; j<=min(i,k); j++){
ans[i] = (ans[i] + g[1][i-j][j])%MOD;
}
}
for(int i=1; i<=n*k; i++) printf("%lld\n",ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律