思路:题目的意思是,游一棵树或者是森林,然后要在某些节点上放置一个警察来防卫,然后每个警察呢只能防卫到自己所在节点和相邻的节点,求所有节点都在直接或间接被防卫的时候需要的最少警察数目。
意思显然,然后就是dp了;对于当前节点的决策是选与不选,dp[i][j],表示第i个节点的是否直接放置警察;
初始化是dp[i][1]=1;
dp[u][1] += min(dp[v][1],dp[v][0]);
dp[u][0] += dp[v][1];
由于存在森林,所以要遍历一遍。
/***************************************** Author :Crazy_AC(JamesQi) Time :2015 File Name : *****************************************/ // #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <algorithm> #include <iomanip> #include <sstream> #include <string> #include <stack> #include <queue> #include <deque> #include <vector> #include <map> #include <set> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <limits.h> using namespace std; #define MEM(a,b) memset(a,b,sizeof a) typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> ii; const int inf = 1 << 30; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; inline int Readint(){ char c = getchar(); while(!isdigit(c)) c = getchar(); int x = 0; while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x; } int n; vector<int> G[1510]; int dp[1510][2]; bool vis[1510]; void dfs(int u,int fa){ vis[u]=true; dp[u][1]=1; dp[u][0]=0; for (int i=0;i<G[u].size();++i){ int v = G[u][i]; if (v==fa || vis[v]) continue; dfs(v,u); dp[u][0] += dp[v][1]; dp[u][1] += min(dp[v][0],dp[v][1]); } } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); while(scanf("%d",&n)!=EOF){ memset(dp, 0,sizeof dp); for (int i = 0;i < n;++i) G[i].clear(); for (int i = 1;i <= n;++i){ int u,num; scanf("%d:(%d)",&u,&num); int v; while(num--){ scanf("%d",&v); G[v].push_back(u); G[u].push_back(v); } } memset(vis, false,sizeof vis); int ans=0; for (int i = 0;i < n;++i){ if (!vis[i]) { dfs(i,-1); ans += min(dp[i][1],dp[i][0]); } } printf("%d\n", ans); } return 0; }