• A-meeting 2019牛客暑期多校第四场 (树的直径)


    题意:

    给你 N 个点以及 N-1 条边将所有点两两连接(树),每个点都有对应编号。现在给你k个点,你要求出这个树上的某个点使得 所给两个点到该点的时间(经过的边数)其中最大的那个为 所能得到的所有答案的最小值。

    思路

    如果仅仅是两个点,那么我们用dijkstra跑一下就可以得到。但是这是k点,切要使这些点能达到的时间最小,我们就会想到树的直径这个概念。

    树的直径
    给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径。

    所以我们就想尽可能的去找这k个点所对应的树的直径,(可以想象一下你有一棵树两个点在树上随机分布,你肯定希望尽量沿着主干走,而不是把多余重复的去走分枝)

    所以我们就利用求树直径的方法:(1)树形dp (2) 两次dfs或者bfs        (这道题选后者比较容易

    所以我们就随便选一个已知点作为起点,第一次找到最远的点,再dfs第二次求得最远路径再除以2即为所求。 所以我们用spfa跑一下最远距离的点再跑回来即是最后的直径(跑最短路的算法都可以)

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define accept 0
    const int maxm = 1e6+5;
    const int maxn = 1e5+5;
    const int inf = 0xffffff;
    struct edge{
        int from;
        int to;
        int w;
        int next;
    }e[maxm];
    int pos[maxn],ans,far;
     
    int head[maxn];
    int vis[maxn];
    int dist[maxn];
    int n,m,top;
      
    void add(int u,int v,int w){
        e[top].from = u;
        e[top].to = v;
        e[top].w = w;
        e[top].next = head[u];
        head[u] = top++;
    }
    void spfa(int s){
        queue<int> q;
        for(int i = 1; i <= n ; i++)
            dist[i] = inf;
        memset(vis,false,sizeof(vis));
        q.push(s);
        dist[s] = 0;
        while(!q.empty()){
            int u  = q.front() ;
            q.pop();
            vis[u] = false ;
            for(int i = head[u] ; ~i ; i = e[i].next){
                int v = e[i].to;
                if(dist[v] > dist[u] + e[i].w){
                    dist[v] = dist[u] + e[i].w;
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        ans = 0;
        for(int i=1;i<=m;i++){
            if(ans < dist[pos[i]]){
                ans = dist[pos[i]];
                far = i;
            }
        }
    }
     
    void init(){
        memset(head,-1,sizeof(head));
        top  =0;
    }
     
    int main(){
        init();
        scanf("%d %d",&n,&m);
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d %d",&u,&v);
            add(u,v,1);
            add(v,u,1);
        }
        int x;
        for(int i=1;i<=m;i++){
            scanf("%d",&pos[i]);
        }
        spfa(pos[1]);
        spfa(pos[far]);
        ans=(ans%2)?(ans/2+1):ans/2;
        printf("%d
    ",ans);
        return accept;
    }
  • 相关阅读:
    ncover
    bash
    .net framework 工具
    keePass
    jersey
    i-jetty
    如何查看set环境变量的更改
    C语言丨如果你不是程序员,绝对看不懂这三个符号!(= 和==、!=)
    忘记 root 密码怎么办?教你4种使用MySQL方式修改密码!(超实用)
    一线城市容不下肉体,二三线城市安放不了灵魂,程序员何处为家?
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11404205.html
Copyright © 2020-2023  润新知