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