POJ 3659——Cell Phone Network

Cell Phone Network
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4416 Accepted: 1562

Description

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 ≤ AN; 1 ≤ BN; AB) 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.

Input

* 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

Output

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

Sample Input

5
1 3
5 2
4 3
3 5

Sample Output

2

Source

USACO 2008 January Gold

 

/*算法思想:
  给一棵树,选择最少的顶点使得整棵树被覆盖
  树形dp
  由于每个节点被覆盖的方式只有两种:被相邻节点覆盖和自己覆盖自己,那么,我们可以给每个节点三个状态:
  f[i][0]:表示节点 i 被它的父亲覆盖,以 i 为根的子树需要覆盖的顶点的最少数量
  f[i][1]:表示节点 i 自己覆盖自己,以 i 为根的子树需要覆盖的顶点的最少数量
  f[i][2]:表示节点 i 被它的儿子覆盖,以 i 为根的子树需要覆盖的顶点的最少数量
  那么就有一下状态转移方程:
  1、f[i][0]+=min(f[i_son][1] , f[i_son][2])
  2、f[i][1]+=min(f[i_son][0] , f[i_son][1] , f[i_son][2]) +1
  3、f[i][2]+=min(f[i_son][1] , f[i_son][2])
  对于第三个状态转移方程:当所有的 f[i_son][2]<f[i_son][1] 时,第 i 个节点实际上是没有被它的儿子覆盖
  的。所以,我们要找一个儿子,用它来覆盖 i 节点;这种情况下,我们需要增加 f[i][2] 的值。增加的值就是
  找 f[i_son][1]-f[i_son][2] 那么,用来覆盖节点 i 的这个儿子应该满足:f[i_son][1]-f[i_son][2] 最小。
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
using namespace std;
struct data
{
    int st,en,next;
} edge[20005];
int f[20005][3],d[20005];
int head[20005],tot;
void add_edge(int st,int en)  //加边
{
    edge[tot].st=st;
    edge[tot].en=en;
    edge[tot].next=head[st];
    head[st]=tot++;
}
void dfs(int u,int fa)  //dfs过程
{
    if(d[u]==1 && u!=1)  //叶子节点
    {
        f[u][0]=0;
        f[u][1]=1;
        f[u][2]=INF;
        return;
    }
    bool fg=true;
    int Min=INF;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        if(edge[i].en==fa) continue;  //树,排除重边
        dfs(edge[i].en,u);
        f[u][0]+=min(f[edge[i].en][1],f[edge[i].en][2]);
        f[u][1]+=min(min(f[edge[i].en][0],f[edge[i].en][1]),f[edge[i].en][2]);
        if(f[edge[i].en][1]<=f[edge[i].en][2])
        {
            f[u][2]+=f[edge[i].en][1];
            fg=false;
        }
        else
        {
            f[u][2]+=f[edge[i].en][2];
            Min=min(f[edge[i].en][1]-f[edge[i].en][2],Min);  //找最小的需要添加的值
        }
    }
    f[u][1]++;
    if(fg) f[u][2]+=Min;
}
int main()
{
    int n,a,b;
    while(scanf("%d",&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        tot=0;
        memset(d,0,sizeof(d));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,b);
            add_edge(b,a);
            d[a]++;
            d[b]++;
        }
        memset(f,0,sizeof(f));
        dfs(1,0);
        if(n!=1) printf("%d\n",min(f[1][1],f[1][2]));
        else printf("1\n");
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值