zoukankan      html  css  js  c++  java
  • P3884 [JLOI2009]二叉树问题 【离线tarjan或数的向上遍历】

    题目

    https://www.luogu.com.cn/problem/P3884

     

     分析

    二叉树的深度、宽度:我们可以使用链式前向星在进行dfs遍历的时候为节点的深度赋值,同时对记录深度的数组的个数加一最后选择深度的最大值,宽度的最大值

    U 到V的距离:这里一般的算法就是使用LCA来寻找这两个节点的共同公共祖先,通过公共祖先的路径就是二者的最短路径

    于是我们可以使用离线的tarjan算法寻找公共祖先,但是本题的特殊性是题目的图是一个有根树而不是一个无根树,所以我们可以通过记录每一个节点的父亲来寻找公共祖先

    方法一

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int deep[200], amount[200],head[200],head2[200],vis[200],father[200],answer[200];
    int n,cnt=0,cnt2=0;
    #define maxn 200
    #define maxm 4000
    struct edge
    {
        int to;
        int next;
    }e[maxm*2];
    struct edge2
    {
        int to;
        int next;
        int num;
    }e2[maxm * 2];
    
    void addedge(int u,int v)
    {
        cnt++;
        e[cnt].to = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
    void addedge2(int u, int v,int w)
    {
        cnt2++;
        e2[cnt2].to = v;
        e2[cnt2].num = w;
        e2[cnt2].next = head2[u];
        head2[u] = cnt2;
    }
    
    int maxdepth = -1, maxwidth = -1;
    void dfs(int p, int fa,int depth)
    {
        deep[p] = depth;
        if (depth > maxdepth)maxdepth = depth;
        amount[depth]++;
        if (amount[depth] > maxwidth)maxwidth = amount[depth];
        for (int i = head[p]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (y == fa)continue;
            dfs(y, p, depth + 1);
        }
    }
    int find(int x)
    {
        if (father[x] == x)return x;
        return father[x] = find(father[x]);
    }
    
    void tarjan(int root)
    {
        vis[root] = 1;
        for (int i = head[root]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (vis[y])continue;
            
            tarjan(y);
            father[y] = root;
        }
        for (int i = head2[root]; i; i = e2[i].next)
        {
            int y = e2[i].to;
            if (vis[y])answer[e2[i].num] = find(y);
        }
    }
    
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 0; i < n - 1; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }
        dfs(1, 0, 1);
        int u, v;
        scanf("%d%d", &u, &v);
        addedge2(u,v,0);
        addedge2(v, u, 0);
    
        for (int i = 0; i <= n; i++)father[i] = i;
        tarjan(1);
        printf("%d
    ", maxdepth);
        printf("%d
    ", maxwidth);
        printf("%d", (deep[u]-deep[answer[0]]) * 2 + deep[v]-deep[answer[0]]);
    }

    方法二

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int deep[200], amount[200],head[200],  father[200];
    int n, cnt = 0;
    #define maxn 200
    #define maxm 4000
    struct edge
    {
        int to;
        int next;
    }e[maxm * 2];
    
    void addedge(int u, int v)
    {
        cnt++;
        e[cnt].to = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
    
    int maxdepth = -1, maxwidth = -1;
    void dfs(int p, int fa, int depth)
    {
        father[p] = fa;
        deep[p] = depth;
        if (depth > maxdepth)maxdepth = depth;
        amount[depth]++;
        if (amount[depth] > maxwidth)maxwidth = amount[depth];
        for (int i = head[p]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (y == fa)continue;
            dfs(y, p, depth + 1);
        }
    }
    
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 0; i < n - 1; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }
        dfs(1, 0, 1);
        int u, v;
        scanf("%d%d", &u, &v);
        printf("%d
    ", maxdepth);
        printf("%d
    ", maxwidth);
        int uu = u, vv = v;
        while (deep[u]!=deep[v])
        {
    
            if (deep[u] > deep[v]) {  u = father[u]; }
            else { v = father[v]; }
        }
        if (u == v) {
            if (deep[uu] < deep[vv])printf("%d", abs(deep[uu] - deep[vv]));
            else printf("%d", abs(deep[vv] - deep[uu]) * 2);
            return 0; 
        }
        while (father[u] != father[v])
        {
            u = father[u];
            v = father[v];
        }
    
        
        printf("%d", (deep[uu] - deep[father[u]]) * 2 + deep[vv] - deep[father[u]]);
    }

    第二种的方法注意要区别两个节点在同一侧还是在不同的两侧

  • 相关阅读:
    【ST】lab01——Junit and Eclemma
    【SPM】hw1——个人房间装修
    【ST】hw2——find the error in the follow case
    【ST】Describe an error from my past projects
    ST homework4 --- 图覆盖
    ST lab1——Junit和覆盖测试的初探
    ST work12——failure,fault,error
    ST work1——印象最深的一个bug DJI 激活时报 SDK_ACTIVE_SDK_VERSION_ERROR
    C# note 06——delegate 和 event
    C# note 05——异常处理
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/13200195.html
Copyright © 2011-2022 走看看