Time Limit: 2000MS | Memory Limit: 10000K | |
Total Submissions: 6607 | Accepted: 3047 |
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)
1 2
还是对树地守卫问题,不过这题是守卫所有的边。节点可以安排士兵,其能守卫相邻的边。求用最少的士兵,守卫所有的边。与皇宫守卫不同。这里只需要看节点是否安排守卫。如果不安排,则其所有子节点均要安排,如果安排守卫,则其子节点状态随意。
//dp[t][0/1] : 根节点为t的子树(0:根节点不安排守卫1:安排)的所有边被守卫的情况下的最小安排士兵数量。 dp[t][0] = sum(dp[ti][1]); dp[t][1] = sum(min(dp[ti][0], dp[ti][1]));
#include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int INF = 999999999; int n; std::vector<int > v[2005]; bool vis[2005]; int dp[2005][2]; void Tdp(int t) { if (v[t].size() == 0) { dp[t][0] = 0; dp[t][1] = 1; return ; } for (int i=0; i<v[t].size(); i++) { Tdp(v[t][i]); dp[t][0] += dp[v[t][i]][1]; dp[t][1] += min(dp[v[t][i]][0], dp[v[t][i]][1]); } dp[t][1]++; } void init() { memset(dp, 0, sizeof(dp)); memset(vis, false, sizeof(vis)); for (int i=0; i<1505; i++) { v[i].clear(); } } int main () { while (scanf ("%d",&n)!=EOF) { init(); for (int i=0; i<n; i++) { int a, b, c; scanf ("%d:(%d)", &a, &b); for (int j=0; j<b; j++) { scanf ("%d", &c); v[a].push_back(c); vis[c] = true; } } int root; for (int i=0; i<n; i++) { if (!vis[i]) { root = i; break; } } Tdp(root); cout << min(dp[root][0], dp[root][1]) << endl; } return 0; }<!--话说这输入真他妈恶心-->
原文地址:http://blog.csdn.net/xuelanghu407/article/details/43700619