• 【HDU 2586 How far away ?】 邻接表+dfs+LCA(最近公共祖先问题)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

    题目大意:有一棵n个节点n-1条边的树。然后给你两个点u,v,让你求u到v的距离。

    解题思路:

         m询问次数比较小,算一下时间复杂度。用邻接表+bfs完全可以过。

         会的就不写了,这里我用邻接表+dfs+LCA。做的最近公共祖先第一题。可做模板。 感谢袁神!!!

       

     1 #pragma comment(linker, "/STACK:1024000000,1024000000")  /// hdu可以用这个操作防止栈溢出,强大~
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 #include <cstring>
     8 using namespace std;
     9 
    10 const int maxn=40005;
    11 int n;
    12 struct Node{   
    13     int v, w;
    14     Node(int v_, int w_){
    15         v= v_, w= w_;
    16     }
    17 };
    18 vector<Node>vt[maxn];  ///  用数组的话肯定存不下的,所以用vector
    19 
    20 int dep[maxn];    ///      记录每个节点离根节点的深度
    21 int father[maxn];  ///     记录上一节点
    22 int dis[maxn];     ///     记录离根节点的距离
    23 
    24 void dfs(int u, int fa, int deep){
    25     father[u]= fa;
    26     dep[u]= deep;
    27     for(int i=0; i<vt[u].size(); ++i){ 
    28         int v= vt[u][i].v;
    29         if( v==fa ) continue; ///特判一下与父节点相连的边,防止进入死循环
    30         dis[v]= dis[u]+vt[u][i].w;
    31         dfs( v, u, deep+1 );
    32     }
    33 }
    34 
    35 int p[maxn][30];
    36 
    37 void Init_LCA(){       ///因为自己的父节点已经dfs找出来了,所以进行打表
    38     for(int j=0; (1<<j)<=n; ++j)
    39         for(int i=1; i<=n; ++i)
    40             p[i][j]= -1;
    41     for(int i=1; i<=n; ++i) p[i][0]= father[i];
    42     for(int j=1; (1<<j)<=n; ++j)   ///以2的指数形式进行操作
    43         for(int i=1; i<=n; ++i)
    44             if( p[i][j-1] != -1 )
    45                 p[i][j]= p[ p[i][j-1] ][ j-1 ];  ///这一步最关键了 
    46 }
    47 
    48 int LCA(int x, int y){
    49     if( dep[x] < dep[y] ) swap( x, y );
    50     int i, lg;
    51     for(lg=0; (1<<lg)<=dep[x]; ++lg);
    52     --lg;
    53     for(i=lg; i>=0; --i) /// 达到同一水平线上(也就是同一rank值);
    54         if( dep[x] - (1<<i) >= dep[y] )
    55             x= p[x][i];
    56     if( x==y ) return x;
    57     /// x,y在同一水平线上,使x,y以相同的步进速度往上走,直到达到LCA处;
    58     for(i=lg; i>=0 ;--i)
    59         if( p[x][i]!=-1 && p[x][i]!=p[y][i] )
    60             x= p[x][i], y= p[y][i];
    61     return father[x];
    62 }
    63 
    64 int main()
    65 {
    66     int m, T, u, v, c;
    67     cin >> T;
    68     while(T--)
    69     {
    70         for(int i=0; i<=n; i++)
    71             vt[i].clear();
    72         cin>>n>>m;
    73         for(int i=1; i<n; ++i){
    74             int x, y, w;
    75             scanf("%d%d%d", &x,&y,&w);
    76             vt[x].push_back( Node( y, w ) );  ///直接存入Node,这样就把点和边一起存进去了
    77             vt[y].push_back( Node( x, w ) );
    78         }
    79 
    80         dis[1]= 0;
    81         dfs(1, -1, 0);
    82         Init_LCA();
    83         while(m--){
    84             int x, y;
    85             scanf("%d%d", &x, &y);
    86             printf("%d\n", dis[x] + dis[y] - 2*dis[ LCA(x, y) ]);  ///x到y的距离为x到根节点的距离加上y到根节点的距离减去两倍的最近公共祖先节点到根节点的距离
    87         }
    88     }
    89 }
  • 相关阅读:
    QuickSort(快速排序)原理及C++代码实现
    MergeSort(归并排序)原理及C++代码实现
    InsertionSort(插入排序)原理及C++代码实现
    基于STC89C516的多游戏实现
    环境变量之classpath配置和临时配置
    搭建Java开发环境之配置环境变量
    一本糊涂账项目
    获取目录-Winform
    读取注册表-64位
    拦截窗体关闭、最大、最小事件
  • 原文地址:https://www.cnblogs.com/kane0526/p/2800625.html
Copyright © 2020-2023  润新知