树形DP
一、在u的子树中,选择一个大小恰好为m的包含u点的连通块,最大的权值和(u,m<=2e3)
这样写虽然是三重循环但是时间复杂度是O(nm)的
void dfs(int u) { sz[u] = 0; for (int v : son[u]) { dfs(v); for (int i = 0; i <= sz[u] + sz[v]; i ++) temp[i] = -INF; for (int i = 0; i <= sz[u]; i ++) for (int j = 0; j <= sz[v]; j ++) temp[i + j] = max(temp[i + j], dp[u][i] + dp[v][j]); for (int i = 0; i <= sz[u] + sz[v]; i ++) dp[u][i] = temp[i]; sz[u] += sz[v]; } sz[u] ++; for (int i = sz[u]; i; i --) dp[u][i] = dp[u][i - 1] + w[u]; }View Code
二、题意跟上题一样但是n<=50000,m<=100
这样的话其实时间复杂度是O(nm)的
sz[u] = 0; for (int v : son[u]) { dfs(v); for (int i = 0; i <= min(sz[u] + sz[v], M); i ++) temp[i] = -INF; for (int i = 0; i <= min(sz[u], M); i ++) for (int j = 0; j <= sz[v] && i + j <= M; j ++) temp[i + j] = max(temp[i + j], dp[u][i] + dp[v][j]); for (int i = 0; i <= min(sz[u] + sz[v], M); i ++) dp[u][i] = temp[i]; sz[u] += sz[v]; } sz[u] ++; for (int i = min(sz[u], M); i; i --) dp[u][i] = dp[u][i - 1] + w[u];View Code
三、每个点都有权值和重量,求一个重量恰好为k的包含根的连通块,最大的权值和(n<=1e3,m<=1e4),不存在输出0
特殊技巧:按dfs序做,r(x)表示序列中跳过x的子树的下一个位置,f[i][j]表示dfs序中 [i, n] 这一段的节点重量等于j的最大权值
f[i][j] = max(f[r(i)][j](不选), f[i + 1][j - vi] + wi),若不选这个节点则子树都跳过
void dfs(int u) {//dfs序 l[u] = cnt ++; id[cnt] = u; for (auto v : son[u]) dfs(v); r[u] = cnt; } void solve() { for (int i = 1; i <= m; i ++) dp[n + 1][i] = -INF; for (int i = n; i; i --) { int u = id[i]; for (int j = 0; j <= m; j ++) { dp[i][j] = dp[r[u] + 1][j]; if (j >= v[u]) dp[i][j] = max(dp[i][j], dp[i + 1][j - v[u]] + w[u]); } } }View Code
标签:总结,cnt,int,dfs,son,权值,动态,规划,View From: https://www.cnblogs.com/Leocsse/p/16896573.html