P2458 [SDOI2006] 保安站岗 - 洛谷
每个点都必须被看守,花费 \(v_i\) 在点 \(i\) 放置一个保安,保安可以看守这个点及这个点所有相邻的点
问使所有点被看守的花费的最小值
代码
| C++ |
|---|
| vector<int> adj[1505];
int dp[1505][3];
// 0 表示自身节点
// 1 表示子节点
// 2 表示父节点
void dfs(int u, int p) {
int res = 0x7fffffff;
for (auto &to : adj[u]) {
if (to == p) continue;
dfs(to, u);
// 如果子节点有, 那么一定要保证一个子节点有.
// 如果子节点有的本来就小, 那么无需选择. 否则我们选择减去孙子节点,加上子节点.
res = min(res, dp[to][0] - min(dp[to][0], dp[to][1]));
// 如果自身节点有, 那么可任意选
dp[u][0] += min({dp[to][0], dp[to][1], dp[to][2]});
// 如果子节点有, 那么先选子节点和孙子节点的最小
dp[u][1] += min(dp[to][0], dp[to][1]);
// 如果父节点有, 那么可选子节点或孙子节点的最小
dp[u][2] += min(dp[to][0], dp[to][1]);
}
dp[u][1] += res;
}
int main() {
int n;
cin >> n;
for (int i = 0 ; i < n ; i++) {
int p, m;
cin >> p >> dp[p][0] >> m;
for (int j = 0 ; j < m ; j++) {
int x;
cin >> x;
adj[p].emplace_back(x);
adj[x].emplace_back(p);
}
}
dfs(1, 0);
cout << min(dp[1][0], dp[1][1]);
return 0;
}
|
P1352 没有上司的舞会 - 洛谷
\(n\) 个节点的树,每个点有价值 \(v_i\),选择点 \(i\) 则不能选择该点的儿子。
问价值和的最大。
代码
| C++ |
|---|
| vector<int> a;
vector<vector<int>> dp, adj;
void dfs(int u) {
dp[u][0] = 0;
dp[u][1] = a[u];
for (auto &i : adj[u]) {
dfs(i);
dp[u][0] += max(dp[i][0], dp[i][1]);
dp[u][1] += dp[i][0];
}
}
int main() {
int n;
cin >> n;
a.resize(n + 1);
adj.resize(n + 1);
dp.resize(n + 1, vector<int>(2));
for (int i = 1 ; i <= n ; i++) cin >> a[i];
vector vis(n + 1, 0);
for (int i = 1 ; i < n ; i++) {
int x, y;
cin >> x >> y;
adj[y].emplace_back(x);
vis[x] = 1;
}
int root = 1;
for (int i = 1 ; i <= n ; i++) {
if (vis[i] == 0) {
root = i;
break;
}
}
dfs(root);
cout << max(dp[root][0], dp[root][1]);
return 0;
}
|
F-树上子链_牛客竞赛动态规划专题班树型dp例题
一棵树, 点权有正有负, 问子链权值和的最大
代码
| C++ |
|---|
| #include <bits/stdc++.h>
using namespace std;
// 2024 OneWan
vector<int> adj[100005];
long long dp[100005];
long long a[100005];
long long ans = -1e18;
void dfs(int u, int p) {
dp[u] = a[u];
for (auto &to : adj[u]) {
if (to == p) continue;
dfs(to, u);
ans = max(ans, dp[u] + dp[to]);
dp[u] = max(dp[u], a[u] + dp[to]);
}
ans = max(ans, dp[u]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for (int i = 1 ; i <= n ; i++) {
cin >> a[i];
}
for (int i = 1 ; i < n ; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1, 0);
cout << ans;
return 0;
}
|
P2014 [CTSC1997] 选课 - 洛谷
代码
| C++ |
|---|
| vector<int> adj[305];
int val[305];
int dp[305][305];
int n, m;
int dfs(int u) {
int p = 1;
dp[u][1] = val[u];
for (auto &v : adj[u]) {
int cnt = dfs(v);
for (int i = min(p, m + 1) ; i > 0 ; i--) {
for (int j = 1 ; j <= cnt && i + j <= m + 1 ; j++) {
dp[u][i + j] = max(dp[u][i + j], dp[u][i] + dp[v][j]);
}
}
p += cnt;
}
return p;
}
int main() {
cin >> n >> m;
for (int i = 1 ; i <= n ; i++) {
int s;
cin >> s >> val[i];
adj[s].emplace_back(i);
}
dfs(0);
cout << dp[0][m + 1];
return 0;
}
|