Time Limit: 2000MS | Memory Limit: 10000K | |
Total Submissions: 7501 | Accepted: 3489 |
Description
Input
Output
Sample Input
4 0:(1) 1 1:(2) 2 3 2:(0) 3:(0) 5 3:(3) 1 4 2 1:(1) 0 2:(0) 0:(0) 4:(0)
Sample Output
1 2
Source
Southeastern Europe 2000
题目大意:
有一个树形村庄,节点与道路相连,问在节点上最少放多少个士兵可以使得所有边被士兵观察到,每个士兵能看到与节点邻接的边。
解题思路:
dp[i][j]表示第i个点是否放置士兵的使得子树边全部被观察到的最小士兵数。dp[i][0]=sigema(dp[j][1]);dp[i][1]=sigema(min(dp[j][0],dp[j][1]),所求的就是min(dp[1][0],dp[1][1]).
#include<stdio.h> #include<map> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<iostream> #define maxn 1550 #define c(a) memset(a,0,sizeof(a)) #define c_1(a) memset(a,-1,sizeof(a)) using namespace std; vector<int>cl[maxn]; int dp[maxn][2]; bool v[maxn]; int dfs(int i, int j) { if (dp[i][j] != -1)return dp[i][j]; int ans = 0; if (j == 1) { ans++; for (int k = 0; k < cl[i].size(); k++) { int a = dfs(cl[i][k], 0); int b = dfs(cl[i][k], 1); ans += min(a, b); } return dp[i][j] = ans; } else { for (int k = 0; k < cl[i].size(); k++) { ans += dfs(cl[i][k], 1); } return dp[i][j] = ans; } } int main() { int n; while (scanf("%d", &n)==1) { c_1(dp); c(v); int a,b,s; for (int i = 0; i<n; i++)cl[i].clear(); for (int i = 0; i < n; i++) { scanf("%d:(%d)",&s ,&a); for (int j = 0; j < a; j++) { scanf("%d", &b); cl[s].push_back(b); v[b] = 1; } } for (int i = 0; i < n; i++)if (cl[i].size() == 0) { dp[i][0] = 0; dp[i][1] = 1; } int x=0; for (int i = 0; i < n; i++)if (!v[i]) x = x+min(dfs(i, 1), dfs(i, 0)); printf("%d\n",x); } }