• 2019牛客多校第四场A meeting——树的直径


    题意:

    一颗 $n$ 个节点的树上标有 $k$ 个点,找一点使得到 $k$ 个关键结点的最大距离最小。

    分析:

    问题等价于求树的直径,最小距离即为直径除2向上取整。

    有两种求法,一是动态规划,对于每个结点,把所有子结点的 $d(i)$ (表示根为 $i$ 的子树中根到叶子的最大距离)都求出来,设 $d$ 值前两大的结点为 $u$ 和 $v$,则 $d(u) + d(v) +2$就是树的直径。

    另一种是两次DFS,从任意一个关键节点开始,找到离它最远的关键结点 $y$,从 $y$ 出发dfs找到新的最远结点 $z$,形成的就是直径。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    struct Edge
    {
        int to, w, next;
    }edges[maxn*2];
    int head[maxn], cnt;
    int n, k;
    int vis[maxn], dis[maxn];      //顶点编号
    set<int>st;
    
    void init()
    {
        memset(head, -1, sizeof(head));
        cnt = 0;
    }
    
    inline void AddEdge(int a, int b, int id)
    {
        edges[id].to = b;
        edges[id].w = 1;
        edges[id].next = head[a];
        head[a] = id;
    }
    
    int dis_v, max_dis;
    void dfs(int v, int dis)
    {
        //printf("%d %d
    ", v, dis);
        vis[v] = 1;
        for(int i = head[v];i != -1;i = edges[i].next)
        {
            int u = edges[i].to;
            if(vis[u])  continue;
            if(st.find(u) != st.end())
            {
                if(dis+1 > max_dis)
                {
                    max_dis = dis + 1;
                    dis_v = u;
                }
            }
            dfs(u, dis+1);
        }
    }
    
    int main()
    {
        init();
        scanf("%d%d", &n, &k);
        for(int i =  0;i < n-1;i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            AddEdge(a, b, ++cnt);
            AddEdge(b, a, ++cnt);
        }
        for(int i = 0;i < k;i++)
        {
            int tmp;
            scanf("%d", &tmp);
            st.insert(tmp);
        }
        dfs(*(st.begin()), 0);  //printf("%d %d
    ", dis_v, max_dis);
        memset(vis, 0, sizeof(vis));
        max_dis = 0;
        dfs(dis_v, 0); //printf("%d %d
    ", dis_v, max_dis);
        printf("%d
    ", (max_dis+1)/ 2);
    
        return 0;
    }
  • 相关阅读:
    SGU 495 Kids and Prizes
    HDU 3853 LOOPS
    HDU 4089 Activation
    HDU 4405 Aeroplane chess
    ZOJ 3329 One Person Game
    POJ 2096 Collecting Bugs
    POJ1573(Robot Motion)
    poj2632(Crashing Robots)
    poj1068(Parencodings)
    poj2506(Tiling)
  • 原文地址:https://www.cnblogs.com/lfri/p/11259301.html
Copyright © 2020-2023  润新知