- 题意:
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。
皇宫各个宫殿的分布,呈一棵树的形状,宫殿可视为树中结点,两个宫殿之间如果存在道路直接相连,则该道路视为树中的一条边。
已知,在一个宫殿镇守的守卫不仅能够观察到本宫殿的状况,还能观察到与该宫殿直接存在道路相连的其他宫殿的状况。
大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。 - 假如是看守边,那么一条边之和它两端的节点有关,因此依靠树的遍历,我们只需要考虑当前节点和子节点即可。但该题目要求的是看守点,那么一个点就会和与它相邻的两个节点的相关,即考虑树中结构,当前节点和它的子节点它的父节点的状态都有关系。
- 而对于某个点,守卫的状态只有放与不放两种状态,于是我们可以根据这两种选择扩展出三种状态。
- Ⅰ(0) 当前节点放置守卫,那么其子节点可以放置守卫也可以不放。
Ⅱ(1) 当前节点不放置守卫并且由它的至少一个子节点来看守。
Ⅲ(2) 当前节点不放置守卫并且由它的父节点来看守,那么其子节点可是可放置或者不放置。 - 状态转移方程
f
[
u
]
[
0
]
=
∑
v
∈
s
o
n
u
m
i
n
{
f
[
v
]
[
0
]
,
f
[
v
]
[
1
]
,
f
[
v
]
[
2
]
}
+
w
i
f
[
u
]
[
2
]
=
∑
v
∈
s
o
n
u
m
i
n
{
f
[
v
]
[
0
]
,
f
[
v
]
[
1
]
}
f
[
u
]
[
1
]
=
m
i
n
{
f
[
u
]
[
2
]
−
m
i
n
(
f
[
v
]
[
0
]
,
f
[
v
]
[
1
]
)
+
f
[
v
]
[
1
]
}
,
{
v
∣
v
∈
s
o
u
u
}
f[u][0] = \sum_{v\in son_u}min\{f[v][0],f[v][1],f[v][2]\} + w_i \\ f[u][2] = \sum_{v\in son_u}min\{f[v][0],f[v][1]\} \\ f[u][1] = min\{f[u][2] - min(f[v][0],f[v][1]) + f[v][1]\} , \{v | v\in sou_u \}
f[u][0]=v∈sonu∑min{f[v][0],f[v][1],f[v][2]}+wif[u][2]=v∈sonu∑min{f[v][0],f[v][1]}f[u][1]=min{f[u][2]−min(f[v][0],f[v][1])+f[v][1]},{v∣v∈souu}
#include <bits/stdc++.h>
using namespace std;
int n,a[10010],head[10010],nxt[10010],to[10010],tot,ind[10010];
void add(int u,int v) {
to[++tot] = v,nxt[tot] = head[u],head[u] = tot;
ind[v] ++;
}
bool vis[10010];
int dp[10010][3];
void dfs(int u) {
vis[u] = true;
dp[u][0] = a[u];
dp[u][1] = 0x3f3f3f3f;
for(int i = head[u];i;i = nxt[i]) {
int v = to[i];
if(vis[v]) continue;
dfs(v);
dp[u][0] += min({dp[v][0],dp[v][1],dp[v][2]});
dp[u][2] += min(dp[v][0],dp[v][1]);
}
for(int i = head[u];i;i = nxt[i]) {
int v = to[i];
dp[u][1] = min(dp[u][1],dp[v][0] + dp[u][2] - min(dp[v][0],dp[v][1]));
}
}
int main() {
cin >> n;
for(int i = 1;i <= n;i ++) {
int id,cost,k; cin >> id >> cost >> k;
a[id] = cost;
for(int j = 1;j <= k;j ++) {
int to; cin >> to;
add(id,to);
}
}
int root;
for(int i = 1;i <= n;i ++) {
if(!vis[i] && !ind[i]) {
root = i;
dfs(i);
}
}
cout << min(dp[root][0],dp[root][1]) << '\n';
return 0;
}