You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.8 KiB
4.8 KiB
##树形DP
专题
【T1
】求一颗树的直径
难度 ★
AcWing
1072
. 树的最长路径
难度 ★★
AcWing
1073
. 树的中心
法一:dfs
来回两遍
从任意一点出发找最长A
,再从A
找最长;和树形DP
没有一丁点关系
缺点:不能处理负权边
void dfs1(int u, int sum) {
st[u] = 1;
if (sum > ans) {
ans = sum; // 记录最大距离
t1 = u; // 记录最远的点t1
}
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
dfs1(j, sum + w[i]);
}
}
void dfs2(int u, int sum) {
st[u] = 1;
if (sum > ans) {
ans = sum; // 记录最大距离
t2 = u; // 记录最远的点t2
}
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
dfs2(j, sum + w[i]);
}
}
...
dfs1(1, 0); // 先找到点距离点1最远的点t
...
dfs2(t1, 0); // 找到距离点t最远的点
法二:树形DP
d1[u]
表示到u
的最长路径。d2[u]
表示到u
的第二长路径,那么易得 d1[u]+ d2[u]
即为经过u
的最长路径
void dfs(int u) {
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
// 走j子树
dfs(j);
// d1[u]:最长路径,d2[u]:次长路径
if (d1[j] + w[i] >= d1[u])
d2[u] = d1[u], d1[u] = d1[j] + w[i]; // 最长路转移
else if (d1[j] + w[i] > d2[u])
d2[u] = d1[j] + w[i]; // 次长路转移
}
// 更新结果
ans = max(ans, d1[u] + d2[u]);
}
###【T2
】覆盖一棵树的最大、最小权值
难度 ★
AcWing
323
战略游戏
对比: 没有上司的舞会:每条边上 最多 选择一个点,求最大权值 战略游戏:每条边上 最少 选择一条点,求最小权值
难度★★★
AcWing
1077
. 皇宫看守
###【T3
】保留一定数量的点、边,求方案数
计蒜客 Mila
的苹果树 【本质是就是二叉苹果树的变形】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2100, M = N << 1;
const int MOD = 998244353;
int e[M], h[N], idx, ne[M];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int n;
int limit[N]; // 以u为根的子树中数量上限
int st[N]; // 是不是访问过
LL f[N][N];
void dfs(int u) {
st[u] = 1; // 访问过了
f[u][0] = 1; // u子树中,放0个苹果的方案是1,此时只能是不管有多少个子结点,都是啥也不能放,方案唯一
if (limit[u]) f[u][1] = 1; // 在u子树中,如果只放1个的话,那么必然是放在u节点上,否则u子树就不存在的,此时方案数是1
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (st[v]) continue;
dfs(v);
// 分组背包
for (int j = limit[u]; j >= 0; j--) // 枚举u子树体积,倒序降维
// Q:为什么这里k=0开始是错的呢?
for (int k = 1; k <= min(j, limit[v]); k++) // 枚举决策,v子树中放资源k个
f[u][j] = (f[u][j] + f[v][k] * f[u][j - k]) % MOD;
}
}
int main() {
freopen("appletree.in", "r", stdin);
freopen("appletree.out", "w", stdout);
memset(h, -1, sizeof h);
cin >> n;
for (int i = 1; i <= n; i++) cin >> limit[i];
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a); // 无向图
}
dfs(1);
int res = 0;
for (int i = 0; i <= limit[1]; i++) res = (res + f[1][i]) % MOD;
printf("%d\n", res);
return 0;
}
51nod
1588
幸运树 【树形dp
统计树上方案数】
P4084
[USACO17DEC
]Barn
Painting
G
P3349
[ZJOI2016
]小星星 TODO