zoukankan      html  css  js  c++  java
  • 牛客多校第四场 A meeting 树的半径

    题意:

    有一棵树,树上有许多人,他们要聚会,找一个点使得所有人到这个点的距离的最大值最小。

    题解:

    首先,以一个有人的点为根,求一个生成树,删掉所有没有人的子树,保证所有的悬挂点(只连接一条边的点)都是有人的节点,以保证后面求出的直径的两端是两个有人节点。为什么非得以有人的节点为根呢?因为如果找了一个没人的节点当根,而这个根又恰好是一个悬挂点,那么可以想象,这个悬挂点可能成为直径的端点。

    其次,求树的直径,就是树上两点的最长距离,这个直径的两个端点必然都是悬挂点。

    直径/2向上取整就是半径,也就是题目所求距离。

    求直径可跑两遍dfs,第一遍从任意点开始,找出与此点距离最大点,第二遍从这个点开始,找出与这个点距离最大点。

    赛时想的是树的重心,wa了,想像一棵树上半部分是一条长链,下半部分是密密麻麻的儿子接在长链一端。然后又想了拓扑求直径,T了。

    但是发现拓扑排序的轮数其实就是树的半径,不知道这个结论有什么用。

    #include<iostream>
    #include<vector>
    #define INF 0x3f3f3f3f
    #include<queue>
    #include<cstring>
    #include<set>
    using namespace std;
    vector<int> lnk[100005];
    vector<int> sclnk[100005];//生成树
    int n;
     
    int scn;//生成树的节点数
    bool ren[100005];
    bool dfs(int fa,int u){
        bool ok=ren[u];
        for(int i=0;i<lnk[u].size();i++){
            int v=lnk[u][i];
            if(v==fa)continue;
            bool tr=dfs(u,v);
            if(tr){
                sclnk[u].push_back(v);
                sclnk[v].push_back(u);
                scn++;
            }
            ok=ok||tr;
        }
        return ok;
    }
    int kg;
    void prt(int fa,int u){
        //把生成树打印出来
        for(int i=1;i<=kg;i++)printf(" ");
        printf("%d
    ",u);
        kg++;
        for(int i=0;i<sclnk[u].size();i++){
            int v=sclnk[u][i];
            if(v==fa)continue;
            prt(u,v);
        }
        kg--;
    }
     
    bool vis[100005];
    int size[100005];
     
    int dis[100005];
    struct P{
        int n,dis;
        P(){}
        P(int n1,int dis1){
            n=n1;dis=dis1;
        }
        friend bool operator >(const P &a,const P &b){
            return a.dis>b.dis;
        }
        friend bool operator <(const P &a,const P &b){
            return a.dis<b.dis;
        }
    };
     
     
    void ddfs(int st) {
        vis[st] = 1;
        for(int i = 0;i<sclnk[st].size();i++) {
            int to =sclnk[st][i];
            if(!vis[to]) {
                dis[to] = dis[st] +1;
                ddfs(to);
            }
        }
    }
     
    int main(){
        //把一个有人的点揪出来当树根
        //删掉无人的子树
        //找出树的直径
        int k;
        scanf("%d %d",&n,&k);
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            lnk[a].push_back(b);
            lnk[b].push_back(a);
        }
        int r1;
        for(int i=1;i<=k;i++){
            int q;
            scanf("%d",&q);
            r1=q;
            ren[q]=1;
        }
        dfs(-1,r1);
    //  prt(r1);
        //求生成树
          
        memset(dis,INF,sizeof dis);
        dis[r1] = 0;
        ddfs(r1);
        //求树的直径
        int maxi=r1;
        for(int i=1;i<=n;i++){
            if(dis[i]!=INF && dis[i]>dis[maxi])maxi=i;
        }
         
        memset(dis,INF,sizeof dis);
        memset(vis,0,sizeof vis);
        dis[maxi] = 0;
        ddfs(maxi);
         
         
        int maxx=0;
        for(int i=1;i<=n;i++){
    //      printf("%d ",dis[i]);
            if(dis[i]!=INF)maxx=max(maxx,dis[i]);
        }
        printf("%d
    ",(maxx+1)/2);
        return 0;
    }
  • 相关阅读:
    用with来打开文本文件
    字符串与列表的转换
    python中的字典两种遍历方式
    Sigar介绍与使用
    tomcat结合nginx使用小结
    AtomicInteger简介
    BeanUtils.copyProperties() 用法
    Spring RPC 入门学习(3)-插入Student对象
    Spring RPC 入门学习(3)-获取Student对象
    Spring RPC 入门学习(2)-获取Map对象
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11257329.html
Copyright © 2011-2022 走看看