题目描述

Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.
Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.
Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.

题目描述
农场主约翰决定给他的每头奶牛一个手机,希望能鼓励它们的社交活动。然而,这需要他在他的N(1≤N≤10,000)个牧场(方便地编号为1..N)上建立手机信号塔,以便他们都能通信。
正好有N-1对牧场相邻,对于任意两个牧场A和B(1≤A≤N;1≤b≤n;A≠B),则存在一个相邻牧场序列,A是该序列中的第一个牧场,B是最后一个牧场。农夫约翰只能在牧场上放置手机信号塔,每个信号塔都有足够的覆盖范围,可以向牧场和牧场附近所有有信号塔的牧场提供服务。
帮助他确定他必须安装的最低数量的塔,以提供移动电话服务到每个牧场。
 

输入描述:

* Line 1: A single integer: N
* Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B

输出描述:

* Line 1: A single integer indicating the minimum number of towers to install

输入描述:

*第一行:单个整数:N
*第2行…N:每行指定一对相邻的牧场,用两个空格分隔的整数:a和B

输出描述:

*第一行:单个整数,表示要安装的最小塔数

示例1

输入

5
1 3
5 2
4 3
3 5

输出

2

说明

The towers can be placed at pastures 2 and 3 or pastures 3 and 5.

塔可以放置在牧场2和3或牧场3和5。

题意:求覆盖一个树所有的点,需要覆盖最小的次数,覆盖一个点需要耗费一次次数,覆盖完以后,那么相邻的点也被覆盖。

对于无向树,直接随便找一个结点作为根,然后把整棵树支起来,就有了根和叶子!
需要一点想象力,反正无向树怎么旋转都可以。
那么寻找当前点的状态,如果一个树都被覆盖,那么这一个点,肯定要么是自己覆盖的,要么是父亲覆盖的,要么是儿子覆盖的,就找到了三种状态。
状态1:自己覆盖
那么对于自己的儿子而言,可以覆盖也可以不覆盖(求min就好了)
状态2:儿子覆盖
那么只要有至少有一个儿子是自己覆盖了的就好了
状态3:父亲覆盖
那么对于自己的儿子,可以是他本身覆盖,也可以是儿子的儿子覆盖。

对于特殊的点,要特殊考虑,有以下两种情况:
1.当前点没有父亲(根结点),那么该点的状态3不存在
2.当前点没有孩子(叶子结点),那么该点状态2不存在

那么对于靠自己和靠父亲来说很简单的能写出状态转移方程:

dp[i][0] = (儿子节点的和)min(dp[u][1],dp[u][2]);

dp[i][1] = (儿子节点的和)min(dp[u][0],dp[u][1],dp[u][2]);

对于最后靠儿子的情况,只要有一个儿子有通信站即可,但究竟是哪一个被点亮呢?那么讨论对儿子来说父亲靠不住就只有两种情况dp[u][1]和dp[u][2]。那么如果有一个儿子节点dp[u][1]<=dp[u][2]的话就不需要付出额外的代价了。如果全部都dp[u][1]>dp[u][2]的话就得选择一个儿子节点将他变成自己建立通信站的情况,但这样必然会付出一些代价,所以我们选取dp[u][1]-dp[u][2]最小的那一个,这样所付出的代价最小。

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int maxn = 10000+10;
int n;
vector<int> son[maxn];
int dp[maxn][3];

void dfs(int x, int fa) {
    int len = son[x].size();
    int add = INT_MAX;
    bool flag = false;
    dp[x][1] = 1;
    for (int i=0;i<len;i++) {
        int next = son[x][i];
        if (next == fa) continue;
        dfs(next, x);
        dp[x][0] += min(dp[next][1], dp[next][2]);
        dp[x][1] += min(dp[next][0],min(dp[next][1], dp[next][2]));
        if (dp[next][1]>dp[next][2]) {
            add = min(dp[next][1]-dp[next][2],add);
        } else {
            flag = true;
        }
    }
    if (flag) {
        dp[x][2] = dp[x][0];
    } else {
        dp[x][2] = dp[x][0]+add;
    }
}

signed main() {
    cin>>n;
    if (n==1) {
        cout<<1<<endl;
        return 0;
    }
    int x, y;
    for (int i=1;i<n;i++) {
        cin>>x>>y;
        son[x].push_back(y);
        son[y].push_back(x);
    }
    dfs(1, 0);
    cout<<min(dp[1][1], dp[1][2]);
    return 0;
}
04-09 21:28