【题意】:给出一棵树,然后每个节点都有一个开关控制这个节点的灯,开始的时候树上所有节点的灯都是关闭的。假如这个节点的开关按了一下,那么这个节点和与他相邻的节点的状态都会改变,on就变off,off变on,求按最少的开关,使所有节点的灯都亮起来。

【题解】:一个树dp题目,之前想了很久,今天下定决心认真推一次,终于给我推出来了。
               设状态dp[u][0]表示按下了u这个点的开关,u及其后代的节点都亮了。
                        dp[u][1]表示不按u这个点的开关,u及其后代的节点都亮了。
                        dp[u][2]表示不按u这个点的开关,u不亮,其后代的节点都亮了。

               显然有:
                        dp[u][0] = ∑dp[v][2] + 1;
                        dp[u][1] = min(奇数个dp[v][0] + 剩下都是dp[v][1]);
                        dp[u][2] = min(偶数个dp[v][0] + 剩下都是dp[v][1]);
                                                                  [其中 v 为 u 的儿子]

                最后,ans = min(dp[1][0], dp[1][1]);

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 using namespace std;
 8 #define pb push_back
 9 #define maxn 105
10 const int inf = 1 << 25;
11 int n;
12 vector<int> g[maxn];
13 int dp[maxn][3];
14 
15 void dfs(int u, int fa) {
16     dp[u][0] = 1, dp[u][1] = inf, dp[u][2] = 0;
17     int size = g[u].size();
18     for(int i = 0; i < size; i++) {
19         int v = g[u][i];
20         if(v == fa) continue;
21         dfs(v, u);
22         int odd = dp[u][1], even = dp[u][2];
23         dp[u][0] += dp[v][2];
24         dp[u][1] = min(even + dp[v][0], odd + dp[v][1]);
25         dp[u][2] = min(odd + dp[v][0], even + dp[v][1]);
26     }
27 }
28 
29 int main() {
30     int u, v;
31     while(~scanf("%d", &n) && n) {
32         for(int i = 0; i < maxn; i++) g[i].clear();
33         for(int i = 0; i < n - 1; i++) {
34             scanf("%d%d", &u, &v);
35             g[u].pb(v);
36             g[v].pb(u);
37         }
38         dfs(1, -1);
39         printf("%d\n", min(dp[1][0], dp[1][1]));
40     }
41     return 0;
42 }