题目:

题目描述

 

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计算一下,为了建立能覆盖到所有草地的通信系统,他最少要建多少座无线电通讯塔。

 


输入格式

 

* 第1行: 1个整数,N

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

 


输出格式

 

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

 


样例输入

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



样例输出

2

输出说明:

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

 

题解:

本题正解树形dp

但是dp是不可能dp的,这辈子都不可能dp的,所以我们来考虑一下贪心做法

注意到每个点都要被选到,而且被选到的方法只有自己被选走或者相邻的点被选走,而且这是一棵树

所以我们先考虑一下在树中深度最大的节点,显然选它的父亲更划算

所以选走它的父亲,并将相邻的点全部扔掉

于是发现对新的树也可以这么做然后搞成一个更小的树直到整棵树没了(同理大法好)

但是你如果暴力去搞的话会$n^2$,所以考虑拿一个数据结构维护一下

因为每次都要选深度最大的点,所以用大根堆来维护深度就好

这样就能$nlogn$维护

至于怎么丢掉这些相邻节点,开一个vis数组来维护一下每个数有没有被丢掉,每次从堆中pop出堆顶的时候判一下它有没有被丢掉就好

正确性?(留给读者思考)

(我举不出反例,所以假定它是正确的,然后也确实能过,不过如果哪位大爷能推翻我这个贪心的话就跟我说一下呗,让我涨一下姿势)

 

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define ll long long
#define inf 1<<30
#define il inline 
#define in1(a) read(a)
#define in2(a,b) in1(a),in1(b)
#define in3(a,b,c) in2(a,b),in1(c)
#define in4(a,b,c,d) in2(a,b),in2(c,d)
il void readl(ll &x){
    x=0;ll f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
il void read(int &x){
    x=0;int f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
using namespace std;
/*===================Header Template=====================*/
#define N 100010
struct edge{int to,next;}e[N<<2];
struct node{
    int dep,id,f;
    bool operator < (const node &x) const {
        return dep<x.dep;
    }
}a[N<<1];
int n,cnt=0,head[N<<2];
void ins(int u,int v){
    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
}
bool vis[N];
void dfs(int x,int f,int dep){
    a[x].dep=dep;
    a[x].f=f;
    a[x].id=x;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f)
            dfs(e[i].to,x,dep+1);
}
priority_queue<node>q;
int main(){
    in1(n);
    for(int i=1;i<n;i++){
        int u,v;
        in2(u,v);
        ins(u,v);ins(v,u);
    }
    dfs(1,1,1);
    for(int i=1;i<=n;i++)q.push(a[i]);
    int ans=0;
    while(!q.empty()){
        node t=q.top();q.pop();
        if(vis[t.id])continue;
        vis[t.id]=1;
        vis[t.f]=1;
        ans++;
        for(int i=head[t.f];i;i=e[i].next){
            int v=e[i].to;
            if(!vis[v])vis[v]=1;
        }
    }
    printf("%d\n",ans);
    return 0;
}