自上而下树状DP,max用法是什么
#include<bits/stdc++.h> using namespace std; #define maxn 110000 int n, val[maxn]; struct Edge{ int nex, to; }edge[maxn<<1]; int head[maxn], cnt; int f[maxn][2]; void add(int from, int to){ edge[++cnt].nex = head[from]; head[from] = cnt; edge[cnt].to = to; return; } void dfs(int u,int fa){ for (int i = head[u]; i; i = edge[i].nex){ int v = edge[i].to; if (v != fa)continue; dfs(v, u); //代表v这个儿子的状态已经被处理了 f[u][0] += max(f[v][0], f[v][1]); //代表u这个点不选,那么v只能进 } return; } const int N = 150; int main() { cin >> n; for (int i = 1; i <= n; i++)cin >> val[i], f[i][1] = val[i]; for (int i = 1; i < n; ++i){ int u, v; cin >> u >> v; add(u, v), add(v, u); } dfs(1, 0); cout << max(f[1][0], f[1][1]); return 0; }
#include<bits/stdc++.h> using namespace std; #define maxn 110 int n, V; int f[maxn][maxn]; int w[maxn],v[maxn]; vector<int>g[maxn]; struct Edge{ int nex, to; }edge[maxn<<1]; int head[maxn], cnt; void add(int from, int to){ edge[++cnt].nex = head[from]; head[from] = cnt; edge[cnt].to = to; return; } void dfs(int u,int fa){ memset(f[u], -0x3f, sizeof(f[u])); // if (v[u] <= V)f[u][v[u]] = w[u];//u这个节点为根 for (int i = head[u]; i; i = edge[i].nex){ int v = edge[i].to; if (v == fa)continue; dfs(v, u); vector<int>nf(f[u], f[u] + V + 1); for (int v1 = 0; v1 <= V; v1++){ for (int v2 = 0; v1 + v2 <= V; v2++){ nf[v1 + v2] = max(nf[v1 + v2], f[u][v1] + f[v][v2]); } } for (int v = 0; v <= V; v++)f[u][v] = nf[v]; } return; } int main() { cin >> n >> V; for (int i = 1; i < n; i++){ int u, v; add(u, v); add(v, u); } dfs(1, 0); int ans = 0; for (int i = 0; i <= V; i++)ans = max(ans,f[1][i]); cout << ans << "\n"; return 0; }
简单来讲,就是当前节点和儿子结点之间有限制关系,那么为了解决这个问题,我们多开一维记录当前节点选的状态即可。
树上背包的trick很常见,掌握十分必要。