POJ 3659

首先这肯定是一个树形DP(因为用tag搜的

一开始用的是2种状态,放没放塔,但是其实还有一种没放塔但是被覆盖的。

然后就自己在草稿纸上画一画,把几个状态转移方式弄出来,0表示没放塔没被覆盖,1表示放了塔,2表示没放塔被覆盖了。

dp[x][0]+=dp[y][2];  因为这个点不放就要保证他的儿子都是被覆盖了的,然后因为2状态肯定比1小,所以加2就行

dp[x][1]加上三个里面最小的之后再加1

dp[x][2]加上所有2之后再加上一个1-2的最小值,因为要保证儿子里面有一个放了

代码如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 const int INF = 0X3f3f3f3f;
 6 int tot = 0, Next[30005], to[30005], head[15005], dp[15005][3], n;
 7 void add(int a, int b) {
 8     Next[tot] = head[a], to[tot] = b;
 9     head[a] = tot++;
10 }
11 void dfs(int x, int pre) {
12     for (int i = head[x]; i != -1; i = Next[i]) {
13         int y = to[i];
14         if (y != pre) {
15             dfs(y, x);
16         }
17     }
18     int minn = INF;
19     for (int i = head[x]; i != -1; i = Next[i]) {
20         int y = to[i];
21         if (y != pre) {
22             dp[x][1] += min(min(dp[y][1], dp[y][0]), dp[y][2]);
23             dp[x][0] += dp[y][2];
24             dp[x][2] += min(dp[y][2], dp[y][1]);
25             minn = min(minn, dp[y][1] - dp[y][2]);
26         }
27     }
28     if (minn > 0 && minn != INF) {
29         dp[x][2] += minn;
30     }
31     dp[x][1]++;
32     if (dp[x][2] == 0) {
33         dp[x][2] = 1;
34     }
35 }
36 int main() {
37     scanf("%d", &n);
38     memset(dp, 0, sizeof(dp));
39     for (int i = 1; i <= n; i++)
40         head[i] = -1;
41     for (int i = 1; i < n; i++) {
42         int x, y;
43         scanf("%d%d", &x, &y);
44         add(x, y);
45         add(y, x);
46     }
47     dfs(1, -1);
48     if (n == 1) {
49         printf("1
");
50         return 0;
51     }
52     printf("%d
", min(dp[1][1], dp[1][2]));
53     return 0;
54 }
View Code
原文地址:https://www.cnblogs.com/i-caigou-TT/p/13842895.html