【題意】:給出一棵樹,然后每個節點都有一個開關控制這個節點的燈,開始的時候樹上所有節點的燈都是關閉的。假如這個節點的開關按了一下,那么這個節點和與他相鄰的節點的狀態都會改變,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 }