zoukankan      html  css  js  c++  java
  • 【NOIP模拟】老大

    题面

    因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图),由于新建的办公室太大以至于要将奖杯要分放在两个不同的地方以便同学们丢硬币进去开光,OB 想请你帮帮他看看奖杯放在哪两个办公室使得在任意一个在劳模办公室做题的小朋友能最快地找到奖杯来开光。

    一句话题意:给出一个 n 个点的树,在两个合适且不同的点放上奖杯,使得每个点到最近的奖杯距离最大值最小

    对于前 60% 的数据,n ≤ 100。
    对于前 80% 的数据,n ≤ 2000。
    对于 80% 的数据,保证树的形态随机。
    对于 100% 的数据,保证 3 ≤ n ≤ 200000。

    分析

    最大值最小,可以看出是二分。

    正向验证行不通,考虑反向验证。

    显然放叶子结点是最不优秀的,贪心地想,放的结点刚好能管到叶子结点肯定是优秀的

    于是定义dp[u]表示u到奖杯的最近距离,叶子节点的距离为二分的值k,而如果当dp[u]==0就一定要放了

    如果最后放的奖杯数量比2个多,肯定是不行的

    代码

    #include<bits/stdc++.h>  
    using namespace std;  
    #define INF 123456789  
    #define N 200020  
    int dp[N],vis[N],first[N],d[N];  
    int n,m,x,y,op,cnt,ans,k,tot,l,r;  
    struct email  
    {  
        int u,v;  
        int nxt;  
    }e[N*4];  
    inline void add(int u,int v)  
    {  
        e[++cnt].nxt=first[u];first[u]=cnt;  
        e[cnt].u=u;e[cnt].v=v;  
    }  
    template<class T>    
    inline void read(T &x)    
    {    
        x=0;    
        static char c=getchar();    
        while(c<'0'||c>'9') c=getchar();    
        while(c>='0'&&c<='9')    
        x=x*10+c-'0',c=getchar();    
    }  
      
    inline void dfs(int u,int f)  
    {  
        int tmp=0,fg=-INF;  
        for(int i=first[u];i;i=e[i].nxt)  
        {  
            int v=e[i].v;  
            if(v==f)continue;  
            ++tmp;dfs(v,u);  
            if(dp[v]>0)dp[u]=min(dp[u],dp[v]-1);  
            else fg=max(fg,dp[v]);  
        }  
        if(tmp==0)dp[u]=k;//在叶结点上赋到奖杯距离为k   
        else if(dp[u]==0)++tot;//必须放置奖杯   
        if(fg!=-INF)  
        {  
            if(dp[u]==INF)dp[u]=k;  
            if(fg+dp[u]>0)dp[u]=fg-1;  
        }  
    }  
      
      
      
    int check()  
    {  
        for(int i=1;i<=n;i++)dp[i]=INF;  
        tot=0;  
        dfs(1,0);  
        if(dp[1]>0)tot++;  
        if(tot<=2)return true;  
        return false;  
    }  
      
      
      
    int main()  
    {  
        read(n);  
        ans=INF;  
        for(int i=1;i<n;i++)  
        {  
            int u,v;  
            read(u),read(v);  
            add(u,v);add(v,u);  
        }  
        l=1,r=n;  
        while(l<=r)  
        {  
            k=l+r>>1;  
            if(check())r=k-1,ans=k;  
            else l=k+1;  
        }  
        printf("%d
    ",ans);  
        return 0;  
      
    }  
  • 相关阅读:
    hdu6229 Wandering Robots 2017沈阳区域赛M题 思维加map
    hdu6223 Infinite Fraction Path 2017沈阳区域赛G题 bfs加剪枝(好题)
    hdu6438 Buy and Resell 买卖物品 ccpc网络赛 贪心
    hdu6441 Find Integer 求勾股数 费马大定理
    bzoj 1176 Mokia
    luogu 3415 祭坛
    bzoj 1010 玩具装箱
    bzoj 3312 No Change
    luogu 3383【模板】线性筛素数
    bzoj 1067 降雨量
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9849698.html
Copyright © 2011-2022 走看看