USACO08JAN 手机网络Cell Phone Network

John想让他的所有牛用上手机以便相互交流(也是醉了。。。),他需要建立几座信号塔在N块草地中。
已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。
(其实就是最小支配集大小)

考虑树上dp

\(f_{u,1}\)表示以u为根的子树中,u选时候的答案

\(f_{u,0}\)表示以u为根的子树中,u不选且儿子不选(也就是u必须要被父亲覆盖)时候的答案

\(f_{u,2}\)表示以u为根的子树中,u不选且至少有一个儿子选时候的答案

于是我们可以得到转移方程

\[\begin{cases} f_{u,1}=1+\sum_{v\in son(u)}min(f_{v,0},f_{v,1},f_{v,2})& \\ f_{u,0}=\sum_{v\in son(u)}f_{v,2}& \\ f_{u,2}=f_{x,1}\ (x\in son(u))+\sum_{v\in son(u)\& v\ne x}min(f_{v,1},f_{v,2}) \end{cases}\]

u选的时候儿子是随便选的

u不选而且儿子不选那么儿子就要被儿子的儿子覆盖到

u不选但儿子选就要保证有一个点是选的,所以我们找到一个x满足\(f_{x,1}-min(f_{x,1},f_{x,2})\)最小,然后剩下的在这个点选或者不选且被儿子覆盖(因为u不选所以不能选择被父亲覆盖)里取较小的

然后注意下根是没有\(f_{1,0}\)的,叶子节点没有\(f_{u,2}\)

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
const int N = 1e4;
using namespace std;
int n,f[N + 5][3];
vector <int> d[N + 5];
void dfs(int u,int fa)
{
    f[u][1] = 1;
    vector <int>::iterator it;
    int mm = N + 5;
    for (it = d[u].begin();it != d[u].end();it++)
    {
        int v = (*it);
        if (v == fa)
            continue;
        dfs(v,u);
        f[u][1] += min(min(f[v][0],f[v][1]),f[v][2]);
        f[u][0] += f[v][2];
        f[u][2] += min(f[v][1],f[v][2]);
        if (mm > f[v][1] - min(f[v][1],f[v][2]))
            mm = f[v][1] - min(f[v][1],f[v][2]);
    }
    f[u][2] += mm;
}
int main()
{
    scanf("%d",&n);
    int u,v;
    for (int i = 1;i < n;i++)
    {
        scanf("%d%d",&u,&v);
        d[u].push_back(v);
        d[v].push_back(u);
    }
    dfs(1,0);
    cout<<min(f[1][2],f[1][1])<<endl;
    return 0;
}
posted @ 2020-06-08 20:35  eee_hoho  阅读(178)  评论(0编辑  收藏  举报