考虑朴素的搜索。对于树上每一个节点,状态只有选或不选。
而很明显:选了当前节点,儿子节点选不选都可以;而假如不选当前节点,就必须选儿子节点.
容易发现,这样产生的搜索树会有大量的重叠。于是考虑记忆化搜索。
使用一个数组d[cur][2]来记录当前节点选 (d[cur][1]) 或不选 (d[cur][0]) 的搜索结果。
最终,时间复杂度为O(n)级别。
下面上代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <cstring> 5 using namespace std; 6 const int MAXN = 1500 + 20; 7 const int INF = 0x7f7f7f7f; 8 9 inline int read() 10 { 11 int x = 0; char ch = getchar(); 12 while(!isdigit(ch)) ch = getchar(); 13 while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); 14 return x; 15 } 16 17 int N; 18 vector<int> g[MAXN]; 19 int d[MAXN][2]; 20 21 inline void clean() 22 { 23 for(int i = 0; i <= N; i++) 24 g[i].clear(); 25 memset(d, 0x7f, sizeof(d)); 26 } 27 28 int dfs(int cur, bool opt, int fa) 29 { 30 if(g[cur].size() == 1 && g[cur][0] == fa) 31 return opt; 32 33 int ans = 0; 34 if(!opt) 35 { 36 for(int i = 0; i < (int) g[cur].size(); i++) 37 { 38 int v = g[cur][i]; 39 if(v != fa) 40 { 41 if(d[v][true] == INF) d[v][true] = dfs(v, true, cur); 42 ans += d[v][true]; 43 } 44 } 45 } 46 else 47 { 48 for(int i = 0; i < (int) g[cur].size(); i++) 49 { 50 int v = g[cur][i]; 51 if(v != fa) 52 { 53 if(d[v][true] == INF) d[v][true] = dfs(v, true, cur); 54 if(d[v][false] == INF) d[v][false] = dfs(v, false, cur); 55 ans += min(d[v][false], d[v][true]); 56 } 57 } 58 ans++; 59 } 60 return ans; 61 } 62 63 inline void solve() 64 { 65 cout<<min(dfs(0, true, 0), dfs(0, false, 0))<<endl; 66 } 67 68 int main() 69 { 70 //freopen("1292.txt", "r", stdin); 71 while(cin>>N) 72 { 73 clean(); 74 int u, v, c; 75 for(int i = 1; i <= N; i++) 76 { 77 u = read(), c = read(); 78 for(int j = 1; j <= c; j++) 79 { 80 v = read(); 81 g[u].push_back(v); 82 g[v].push_back(u); 83 } 84 } 85 solve(); 86 } 87 return 0; 88 }