您的位置:首页 > 其它

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

2012-12-04 00:11 447 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

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

解题思路:

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

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

#pragma comment(linker, "/STACK:1024000000,1024000000")  /// hdu可以用这个操作防止栈溢出,强大~
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn=40005;
int n;
struct Node{
int v, w;
Node(int v_, int w_){
v= v_, w= w_;
}
};
vector<Node>vt[maxn];  ///  用数组的话肯定存不下的,所以用vector

int dep[maxn];    ///      记录每个节点离根节点的深度
int father[maxn];  ///     记录上一节点
int dis[maxn];     ///     记录离根节点的距离

void dfs(int u, int fa, int deep){
father[u]= fa;
dep[u]= deep;
for(int i=0; i<vt[u].size(); ++i){
int v= vt[u][i].v;
if( v==fa ) continue; ///特判一下与父节点相连的边,防止进入死循环
dis[v]= dis[u]+vt[u][i].w;
dfs( v, u, deep+1 );
}
}

int p[maxn][30];

void Init_LCA(){       ///因为自己的父节点已经dfs找出来了,所以进行打表
for(int j=0; (1<<j)<=n; ++j)
for(int i=1; i<=n; ++i)
p[i][j]= -1;
for(int i=1; i<=n; ++i) p[i][0]= father[i];
for(int j=1; (1<<j)<=n; ++j)   ///以2的指数形式进行操作
for(int i=1; i<=n; ++i)
if( p[i][j-1] != -1 )
p[i][j]= p[ p[i][j-1] ][ j-1 ];  ///这一步最关键了
}

int LCA(int x, int y){
if( dep[x] < dep[y] ) swap( x, y );
int i, lg;
for(lg=0; (1<<lg)<=dep[x]; ++lg);
--lg;
for(i=lg; i>=0; --i) /// 达到同一水平线上(也就是同一rank值);
if( dep[x] - (1<<i) >= dep[y] )
x= p[x][i];
if( x==y ) return x;
/// x,y在同一水平线上,使x,y以相同的步进速度往上走,直到达到LCA处;
for(i=lg; i>=0 ;--i)
if( p[x][i]!=-1 && p[x][i]!=p[y][i] )
x= p[x][i], y= p[y][i];
return father[x];
}

int main()
{
int m, T, u, v, c;
cin >> T;
while(T--)
{
for(int i=0; i<=n; i++)
vt[i].clear();
cin>>n>>m;
for(int i=1; i<n; ++i){
int x, y, w;
scanf("%d%d%d", &x,&y,&w);
vt[x].push_back( Node( y, w ) );  ///直接存入Node,这样就把点和边一起存进去了
vt[y].push_back( Node( x, w ) );
}

dis[1]= 0;
dfs(1, -1, 0);
Init_LCA();
while(m--){
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", dis[x] + dis[y] - 2*dis[ LCA(x, y) ]);  ///x到y的距离为x到根节点的距离加上y到根节点的距离减去两倍的最近公共祖先节点到根节点的距离
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: