题意:
给定一棵树, 问最少要占据多少个点才能守护所有边
分析:
树形DP枚举每个点放与不放
树形DP:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = ;
int dp[maxn][];
//用DP[i][0]来表示该点没有放兵,以这个点为根的子树所需的最少兵数。
//用DP[i][1]来表示该点放兵,以这个点为根的子树所需的最少兵数。 int father[maxn]; //记录每个节点父亲
int vis[maxn];
int N;
int root = ;
int dfs(int node){
dp[node][] = , dp[node][] = ;
vis[node] = ;
for(int i = ; i < N; i++){
if(father[i] == node && !vis[i]){
dfs(i);
dp[node][] += dp[i][]; //父亲不放, 儿子必须放
dp[node][] += min(dp[i][], dp[i][]);//父亲节点放了, 取儿子节点的最小值
}
}
return min(dp[node][], dp[node][]);
}
int main() {
while(~scanf("%d", &N)) {
memset(father, -, sizeof(father));
memset(dp, , sizeof(dp));
memset(vis, , sizeof(vis));
int root = -;
for(int i = ; i < N; i++){
int u ,v ,k;
scanf("%d:(%d)", &u, &k);
if(root == -) root = u; //the first node is root;
for(int j = ; j < k; j++){
scanf("%d", &v);
father[v] = u;
}
} cout << dfs(root) << "\n";
}
return ;
}