自下而上的树形DP
01例题
选择若干个点,使得没有相邻的两个点均被选择。最大化被选择的点的点权和。
3 1 2 3 2 1 3 1 =>5 #include<bits/stdc++.h> using namespace std; const int N = 100005; int n, a[N]; long long dp[N][2]; vector<int> e[N]; void dfs(int u){ for (auto v : e[u]){ dfs(v); dp[u][1] += dp[v][0]; dp[u][0] += max(dp[v][0], dp[v][1]); } dp[u][1] += a[u]; } int main() { cin >> n; set<int>st; for (int i = 1; i <= n; i++)cin >> a[i], st.insert(i); for (int i = 1, x, y; i < n; i++){ cin >> x >> y; e[y].push_back(x); st.erase(x); } int rt = *st.begin(); dfs(rt); cout << max(dp[rt][0], dp[rt][1]); return 0; }
02最小点覆盖
#include<bits/stdc++.h> using namespace std; const int N = 100005; int n, dp[N][2]; vector<int> e[N]; void dfs(int u,int fa ){ for (auto v : e[u]){ if (v == fa)continue; dfs(v, u); dp[u][0] += dp[v][1]; dp[u][1] += min(dp[v][0], dp[v][1]); } dp[u][1] += 1; } int main() { cin >> n; for (int i = 1; i <n; i++) { int x, y; cin >> x >> y; e[x].push_back(y); e[y].push_back(x); } dfs(1, 0); cout << min(dp[1][0], dp[1][1]); return 0; }
03最小支配集
#include <bits/stdc++.h> using namespace std; const int N=100005; vector<int>e[N]; long long a[N],dp[N][3]; int d[N]; int n; void dfs(int u) { long long minn=1e18; for (auto v:e[u]) { dfs(v); dp[u][0]+=min({dp[v][0],dp[v][1],dp[v][2]}); dp[u][1]+=min(dp[v][0],dp[v][1]); minn=min(minn,dp[v][0]-min(dp[v][0],dp[v][1])); dp[u][2]+=dp[v][1]; } dp[u][0]+=a[u]; dp[u][1]+=minn; } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cin>>n; for (int i=1;i<=n;++i) { int id,m; cin>>id; cin>>a[id]; cin>>m; while (m--) { int x; cin>>x; e[id].push_back(x); d[x]++; } } int rt; for (int i=1;i<=n;++i) if (d[i]==0) rt=i; dfs(rt); cout<<min(dp[rt][0],dp[rt][1]); return 0; }