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;  
      
    }  
  • 相关阅读:
    75张图带你了解网络设备、网络地址规划、静态路由、实战演练
    37张图详解MAC地址、以太网、二层转发、VLAN
    用Python计算最长公共子序列和最长公共子串(转)
    python多线程为什么不能利用多核cpu
    python实现leetcode算法题库-maxLengthofRepeatedSubarray-最长公共子序列(718)
    python实现leetcode算法题库-twoSum-两数之和(1)
    python字符串与列表及字典的相互转化
    python sorted函数的使用
    python 2/3重定向输出文件
    elasticsearch查询时设置最大返回数 max_result_window | 限制字段总数超1000
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9849698.html
Copyright © 2011-2022 走看看