Parabola
2018-12-08 15:51:45
搞完这题真的深有体会呀
状态:
含义
那么现在的问题就是如何得到这个最优的x了,可以这么思考,如果x不是最优的,那么对于x来说,一定存在另一个子节点y满足
推得
两式同时减去相同的部分,有
即
所以对于最优的节点x,
另外写代码的时候要多考虑几个小地方,像什么初始值什么的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN = 1500 + 5;
int n , p[MAXN] , f[MAXN];
int rt , dp[MAXN][3];
bool hfa[MAXN];
vector <int> G[MAXN];
//0 有保安 ,1没保安但被父控制 ,2没保安未被控制
void dfs(int u) {
int x = 0;
dp[u][0] = p[u];
for(int i = 0 , v ; i < (int)G[u].size() ; ++i) {
dfs(v = G[u][i]);
dp[u][0] += min(min(dp[v][0] , dp[v][1]) , dp[v][2]);
dp[u][1] += min(dp[v][0] , dp[v][2]);
if((dp[x][0] - min(dp[x][0] , dp[x][2])) > dp[v][0] - min(dp[v][0] , dp[v][2])) x = v;
}
dp[u][2] = dp[x][0];
for(int i = 0 , v ; i < (int)G[u].size() ; ++i) {
if((v = G[u][i]) == x) continue;
dp[u][2] += min(dp[v][0] , dp[v][2]);
}
}
int main() {
dp[0][0] = 1 << 30;
scanf("%d" , &n);
for(int i = 1 , x , k , m , v ; i <= n ; ++i) {
scanf("%d %d %d" , &x , &k , &m);
p[x] = k;
while(m--) {
scanf("%d" , &v);
hfa[v] = true;
G[x].push_back(v);
}
}
for(int i = 1 ; i <= n ; ++i) if(!hfa[i]){
rt = i;
break;
}
dfs(rt);
printf("%d\n" , min(dp[rt][0] , dp[rt][2]));
return 0;
}