传送门: https://www.luogu.com.cn/problem/P2458
题意
给
一
棵
树
,
在
树
上
安
置
保
安
,
一
条
边
的
两
个
端
点
至
少
安
置
一
个
保
安
,
保
安
都
有
费
用
。
给一棵树,在树上安置保安,一条边的两个端点至少安置一个保安,保安都有费用。
给一棵树,在树上安置保安,一条边的两个端点至少安置一个保安,保安都有费用。
问
符
合
情
况
的
最
小
费
用
是
多
少
。
问符合情况的最小费用是多少。
问符合情况的最小费用是多少。
思路
因 为 一 条 边 的 两 个 端 点 必 须 要 有 一 个 , 可 以 有 两 个 , 所 以 这 是 不 限 制 父 亲 和 儿 子 关 系 的 。 因为一条边的两个端点必须要有一个,可以有两个,所以这是不限制父亲和儿子关系的。 因为一条边的两个端点必须要有一个,可以有两个,所以这是不限制父亲和儿子关系的。
如 果 一 条 边 的 两 个 端 点 都 选 , 那 一 定 不 会 是 最 小 费 用 , 所 以 只 需 要 选 一 点 即 可 。 如果一条边的两个端点都选,那一定不会是最小费用,所以只需要选一点即可。 如果一条边的两个端点都选,那一定不会是最小费用,所以只需要选一点即可。
对
于
一
个
点
选
不
选
,
对
父
亲
和
儿
子
选
不
选
都
有
影
响
,
所
以
设
f
[
u
]
[
0
/
1
/
2
]
。
对于一个点选不选,对父亲和儿子选不选都有影响,所以设f[u][0/1/2]。
对于一个点选不选,对父亲和儿子选不选都有影响,所以设f[u][0/1/2]。
f
[
u
]
[
]
表
示
以
u
为
根
的
子
树
。
f[u][]表示以u为根的子树。
f[u][]表示以u为根的子树。
- f [ u ] [ 0 ] 表 示 u 自 己 选 f[u][0]表示u自己选 f[u][0]表示u自己选
- f [ u ] [ 1 ] 表 示 自 己 不 选 , 儿 子 选 f[u][1]表示自己不选,儿子选 f[u][1]表示自己不选,儿子选
- f [ u ] [ 2 ] 表 示 自 己 不 选 , 父 亲 选 f[u][2]表示自己不选,父亲选 f[u][2]表示自己不选,父亲选
转 移 方 程 : 转移方程: 转移方程:
自 己 选 , 不 妨 碍 其 他 点 的 选 择 , 即 自己选,不妨碍其他点的选择,即 自己选,不妨碍其他点的选择,即
- f [ u ] [ 0 ] + = ∑ v ∈ g [ u ] m i n ( f [ v ] [ 0 ] , f [ v ] [ 1 ] , f [ v ] [ 2 ] ) f[u][0]+=\sum_{v\in g[u]}min(f[v][0],f[v][1],f[v][2]) f[u][0]+=∑v∈g[u]min(f[v][0],f[v][1],f[v][2])
父 亲 选 , 所 以 自 己 不 用 选 了 , 只 需 要 加 上 儿 子 的 最 小 费 用 , 即 父亲选,所以自己不用选了,只需要加上儿子的最小费用,即 父亲选,所以自己不用选了,只需要加上儿子的最小费用,即
- f [ u ] [ 2 ] + = ∑ v ∈ g [ u ] m i n ( f [ v ] [ 0 ] + f [ v ] [ 1 ] ) f[u][2]+=\sum_{v\in g[u]} min(f[v][0]+f[v][1]) f[u][2]+=∑v∈g[u]min(f[v][0]+f[v][1])
儿 子 选 , 对 于 所 有 儿 子 , 肯 定 不 会 全 部 都 选 , 选 择 最 小 的 儿 子 即 可 , 即 儿子选,对于所有儿子,肯定不会全部都选,选择最小的儿子即可,即 儿子选,对于所有儿子,肯定不会全部都选,选择最小的儿子即可,即
- f [ u ] [ 1 ] + = ∑ v ∈ g [ u ] 除 最 小 f [ v ] [ 1 ] + f [ v 最 优 ] [ 0 ] f[u][1]+=\sum_{v\in g[u]除最小}f[v][1]+f[v_{最优}][0] f[u][1]+=∑v∈g[u]除最小f[v][1]+f[v最优][0]
对 于 f [ u ] [ 1 ] , 我 们 怎 么 找 到 最 小 的 呢 ? 对于f[u][1],我们怎么找到最小的呢? 对于f[u][1],我们怎么找到最小的呢?
记 录 m n = m i n ( m n , f [ v ] [ 0 ] − f [ v ] [ 1 ] ) 记录mn=min(mn,f[v][0]-f[v][1]) 记录mn=min(mn,f[v][0]−f[v][1])
bool flag = 1;
if(f[v][0] <= f[v][1]) {
flag = 0;
f[u][1] += f[v][0];
}
else {
f[u][1] += f[v][1];
mn = min(mn, f[v][0] - f[v][1]);
}
}
if(flag) f[u][1] += mn;
Code
#include "bits/stdc++.h"
using namespace std;
const int N = 1e4 + 10;
vector<int> g[N];
int val[N];
int f[N][3];
void dfs(int u, int fa) {
f[u][0] = val[u];
bool flag = 1;
int mn = 1e9;
for(auto v : g[u]) {
if(v == fa) continue;
dfs(v, u);
f[u][0] += min(f[v][0], min(f[v][1], f[v][2]));
f[u][2] += min(f[v][0], f[v][1]);
if(f[v][0] <= f[v][1]) {
flag = 0;
f[u][1] += f[v][0];
}
else {
f[u][1] += f[v][1];
mn = min(mn, f[v][0] - f[v][1]);
}
}
if(flag) f[u][1] += mn;
}
void solve() {
int n; cin >> n;
for(int i = 1;i <= n; i++) {
int id, m; cin >> id >> val[id] >> m;
for(int j = 1;j <= m; j++) {
int v; cin >> v;
g[v].eb(id);
g[id].eb(v);
}
}
dfs(1, -1);
cout << min(f[1][0], f[1][1]) << endl;
}
signed main() {
solve();
}