题目链接: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 }