[知识点] 4.2.3 动态规划进阶模型——树形/DAG/数位DP

前言

本文主要介绍动态规划的集中进阶模型——树形 DP、DAG 上的 DP、数位 DP。不同于之前的基础模型的一点是,它们的状态并非单纯地建立在线性关系或者二维空间上,而是在树结构,图,二进制数位上进行转移,相对之下可能更麻烦,但其实也是换汤不换药的。

子目录列表

1、树形 DP

2、DAG 上的 DP

3、数位 DP

4.2.3 树形 / DAG / 数位 DP

1、树形 DP

顾名思义,在树结构上进行动态规划,没有太多概念可言,直接以一道经典的例题引入好了。

【没有上司的舞会】某大学有 n 个职员,编号为 1 ~ n 。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 ai,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

在树状结构找子问题其实还是挺方便的,所有节点只和其子节点和唯一父节点相连,利用这点性质来切入:假设以 i 为根的树为一棵子树,如果 i 参加舞会,则其所有子节点均不能参加;如果不参加,则子节点可参加可不参加;再向其所有儿子节点递归,以此类推。

状态定义:f[i] 表示 “以 i 为根节点的子树可以获得的最大快乐指数”;

由于对于任何一个节点又存在两个状态——参加与不参加,所以还需要增加一维 0 / 1,表示是否参加舞会。

状态转移:f[i][0] = ∑max(f[j][0], f[j][1]);

     f[i][1] = ∑f[j][0] + a[i],j 表示 i 的儿子节点。

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define MAXN 6005
 5 
 6 struct Edge {
 7     int v, nxt;
 8 } e[MAXN];
 9 
10 int n, o, u, v, tot, f[MAXN][2], nr[MAXN], h[MAXN];
11 
12 void addEdge(int u, int v) {
13     e[++o] = (Edge) {v, h[u]}, h[u] = o;
14 }
15 
16 void dfs(int o, int fa) {
17     for (int x = h[o]; x; x = e[x].nxt) {
18         int v = e[x].v;
19         if (v == fa) continue;
20         dfs(v, o);
21         f[o][1] += f[v][0];
22         f[o][0] += max(f[v][0], f[v][1]);
23     }
24 }
25 
26 int main() {
27     cin >> n;
28     for (int i = 1; i <= n; i++) cin >> f[i][1];
29     for (int i = 1; i <= n; i++)
30         cin >> u >> v, addEdge(v, u), nr[u] = 1;
31     for (int i = 1; i <= n; i++) {
32         if (nr[i]) continue;
33         dfs(i, 0);
34         cout << max(f[i][0], f[i][1]);
35         break;
36     }
37     return 0;
38 } 

2、DAG 上的 DP

3、数位 DP

猜你喜欢

转载自www.cnblogs.com/jinkun113/p/12723563.html
今日推荐