160 lines
4.8 KiB
Markdown
160 lines
4.8 KiB
Markdown
##树形$DP$专题
|
||
|
||
### 【$T1$】求一颗树的直径
|
||
**难度 ★**
|
||
**[$AcWing$ $1072$. 树的最长路径](https://www.cnblogs.com/littlehb/p/15784687.html)**
|
||
|
||
**难度 ★★**
|
||
**[$AcWing$ $1073$. 树的中心](https://www.cnblogs.com/littlehb/p/15786805.html)**
|
||
|
||
**[$AcWing$ $1075$. 数字转换](https://www.cnblogs.com/littlehb/p/15787542.html)**
|
||
|
||
#### 法一:$dfs$来回两遍
|
||
从任意一点出发找最长$A$,再从$A$找最长;和树形$DP$没有一丁点关系
|
||
**缺点**:不能处理负权边
|
||
```cpp {.line-numbers}
|
||
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$的最长路径
|
||
|
||
```cpp {.line-numbers}
|
||
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$ 战略游戏](https://www.cnblogs.com/littlehb/p/15788291.html)**
|
||
|
||
**难度★**
|
||
**[$AcWing$ $285$. 没有上司的舞会](https://www.cnblogs.com/littlehb/p/15468981.html)**
|
||
|
||
**对比:**
|
||
没有上司的舞会:每条边上 **最多** 选择一个点,**求最大权值**
|
||
战略游戏:每条边上 **最少** 选择一条点,**求最小权值**
|
||
|
||
**难度★★★**
|
||
**[$AcWing$ $1077$. 皇宫看守](https://www.cnblogs.com/littlehb/p/15788813.html)**
|
||
|
||
###【$T3$】保留一定数量的点、边,求方案数
|
||
|
||
**[$AcWing$ $1074$ . 二叉苹果树 ](https://www.cnblogs.com/littlehb/p/15788100.html)**
|
||
|
||
**[计蒜客 $Mila$的苹果树](https://www.jisuanke.com/problem/T3702)** 【**本质是就是二叉苹果树的变形**】
|
||
|
||
```cpp {.line-numbers}
|
||
#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$ 幸运树](https://www.cnblogs.com/littlehb/p/17203577.html)** 【树形$dp$统计树上方案数】
|
||
|
||
**[$P4084$ [$USACO17DEC$]$Barn$ $Painting$ $G$](https://www.cnblogs.com/littlehb/p/17204104.html)**
|
||
|
||
**[$P3349$ [$ZJOI2016$]小星星](https://www.luogu.com.cn/problem/P3349)** TODO
|
||
|
||
https://blog.csdn.net/A_Bright_CH/article/details/83443279 |