树形DP + 状态机
对于每个节点u有三种情况:
1.u点放置哨兵,u被自己观察到,那么u的子节点可放可不放,取min
2.u不放哨兵,但是u的任一子节点放置了哨兵,u被子节点观察到
3.u不放哨兵,u的父节点放置了哨兵,u被父节点观察到,那么u的子节点可放可不放
所以状态机定义三种模型
状态表示:
f[u][0]表示点u不放哨兵,u被父节点观察到
f[u][1]表示点u不放哨兵,u被子节点观察到
f[u][2]表示点u放哨兵,u被自己观察到
状态转移:
j 表示u的子节点
f[u][0] = ∑ min(f[j][1],f[j][2])
f[u][2] = ∑ min(f[j][0], f[j][1], f[j][2]) + w[u] // u放置哨兵,花费至少为为w[u]
对于f[u][1],找到一个子节点k观察到u,其余子节点j可放可不放
所以f[u][1] = min(f[k][2] + ∑ min(f[j][1], f[j][2]))
#include <iostream>
#include <algorithm>
#include <cstring>
const int N = 1505;
int w[N];
int h[N], e[N], ne[N], idx;
int f[N][3];
bool st[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u) {
f[u][2] = w[u];
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
dfs(j);
f[u][0] += std::min(f[j][1], f[j][2]);
f[u][2] += std::min({f[j][0], f[j][1], f[j][2]});
}
f[u][1] = 1e9;
int& v = f[u][1];
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
// f[u][0]表示了sum{min(f[j][1], f[j][2])}
// 用总和减去当前子节点的贡献就得到剩余可放可不放的子节点的花费
v = std::min(v, f[u][0] + f[j][2] - std::min(f[j][1], f[j][2]));
}
}
int main() {
int n;
std::cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++ ) {
int a, cost, m;
std::cin >> a >> cost >> m;
w[a] = cost;
while (m -- ) {
int b;
std::cin >> b;
add(a, b);
st[b] = true;
}
}
int root = 1;
while (st[root]) root ++ ;
dfs(root);
std::cout << std::min(f[root][1], f[root][2]) << '\n';
return 0;
}
标签:std,min,int,看守,ne,哨兵,皇宫,节点 来源: https://www.cnblogs.com/zjh-zjh/p/16701364.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。