bzoj 1596: [Usaco2008 Jan]电话网络

1596: [Usaco2008 Jan]电话网络

Description

Farmer John决定为他的所有奶牛都配备手机,以此鼓励她们互相交流。不过,为此FJ必须在奶牛们居住的N(1 <= N <= 10,000)块草地中选一些建上无线电通讯塔,来保证任意两块草地间都存在手机信号。所有的N块草地按1..N 顺次编号。 所有草地中只有N-1对是相邻的,不过对任意两块草地A和B(1 <= A <= N; 1 <= B <= N; A != B),都可以找到一个以A开头以B结尾的草地序列,并且序列中相邻的编号所代表的草地相邻。无线电通讯塔只能建在草地上,一座塔的服务范围为它所在的那块草地,以及与那块草地相邻的所有草地。 请你帮FJ计算一下,为了建立能覆盖到所有草地的通信系统,他最少要建多少座无线电通讯塔。

Input

* 第1行: 1个整数,N

* 第2..N行: 每行为2个用空格隔开的整数A、B,为两块相邻草地的编号

Output

* 第1行: 输出1个整数,即FJ最少建立无线电通讯塔的数目

Sample Input

5
1 3
5 2
4 3
3 5
输入说明:
Farmer John的农场中有5块草地:草地1和草地3相邻,草地5和草地2、草地
4和草地3,草地3和草地5也是如此。更形象一些,草地间的位置关系大体如下:
(或是其他类似的形状)
4 2
| |
1--3--5

Sample Output

2
输出说明:
FJ可以选择在草地2和草地3,或是草地3和草地5上建通讯塔。

HINT

查错查了半天。。。。

直接讲题解吧,还是比较裸的树形DP

f[x][0]表示这个点不选

f[x][1]表示这个选

f[x][2]表示这个点不会选但是至少会选一个儿子

转移看代码吧。。

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=10005;
int n,i,x,y,f[N][3];
int tot,head[N],Next[N<<1],to[N<<1];
void add(int x,int y)
{
    tot++;
    to[tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
void dfs(int x,int pre)
{
    f[x][0]=0;
    f[x][1]=1;
    f[x][2]=1000000;
    int i,y,s=0;
    for(i=head[x];i!=-1;i=Next[i])
        if(to[i]!=pre) dfs(to[i],x);
    for(i=head[x];i!=-1;i=Next[i])
    {
        y=to[i];
        if(y==pre) continue;
        f[x][1]+=min(f[y][2],min(f[y][1],f[y][0]));
        f[x][0]+=min(f[y][2],f[y][1]);
        s+=min(f[y][2],f[y][1]);
    }
    for(i=head[x];i!=-1;i=Next[i])
    {
        y=to[i];
        if(y==pre) continue;
        f[x][2]=min(f[x][2],f[y][1]+s-min(f[y][2],f[y][1]));
    }
}
int main()
{
    scanf("%d",&n);
    for(i=1;i<=n;i++) head[i]=-1;
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    cout<<min(f[1][2],f[1][1]);
    return 0;
}

 

 
posted @ 2016-06-06 11:57  lwq12138  阅读(218)  评论(0编辑  收藏  举报