1. 程式人生 > >[bzoj 1596][Usaco2008 Jan]電話網絡

[bzoj 1596][Usaco2008 Jan]電話網絡

pla top opera name 數組 cst 深度 所有 long long

題目:

題目描述

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;
}

[bzoj 1596][Usaco2008 Jan]電話網絡