【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 }

你可能感兴趣的:(HDU)