How far away ?

There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
InputFirst line is a single integer T(T<=10), indicating the number of test cases. 
  For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n. 
  Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.OutputFor each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1
Sample Output
10
25
100

100

题目大意:lac问题,给出一个图,问从一个点到另一个点的路径是多少,其中两个点之间的路径唯一。

解题思路:所谓的lac就是最近的公共祖先问题。这里是tarjan 算法。可以把图建成一棵树,从树根开始遍历,遍历每个节点,并计算每个节点到根节点的最短路径。之后根据遍历的先后顺序所标记的数组值,运用并查集判断两个节点的最近公共祖先。则这两个点之间的路径可以用着两个点到根节点的路径之和减去最近公共祖先到根节点路径的2倍,即为所求。

代码:

#include<stdio.h>
#include<string.h>
typedef struct stu{
int x,w;
int next;
}st;
int m,n,con;
st s[80010];
int dis[40010],pre[40010],f[40010];
int x[40010],y[40010],z[40010];
bool vis[40010];
void add(int x,int y,int w)
{
s[con].x=x;
s[con].w=w;
s[con].next=pre[y];
pre[y]=con++;
s[con].x=y;
s[con].w=w;
s[con].next=pre[x];
pre[x]=con++;
}
int find(int x)
{
if(x==f[x])
 return x;
else
return f[x]=find(f[x]);
}
void tarjan(int u)
{
int i;
vis[u]=true;
f[u]=u;
for(i=0;i<m;i++)
{
if(x[i]==u&&vis[y[i]])
 z[i]=find(y[i]);
if(y[i]==u&&vis[x[i]])
 z[i]=find(x[i]);
}
for(i=pre[u];i!=-1;i=s[i].next)
{
if(!vis[s[i].x])
{
dis[s[i].x]=dis[u]+s[i].w;
tarjan(s[i].x);
f[s[i].x]=u;
}
}
}
int main()
{
int i,j,k,m,n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int u,v,w;
con=0;
memset(pre,-1,sizeof(pre));
for(i=0;i<n-1;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(i=1;i<=n;i++)
x[i]=y[i]=z[i]=0;
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
x[i]=u;
y[i]=v;
}
memset(vis,false,sizeof(vis));
dis[1]=0;
tarjan(1);
for(i=0;i<m;i++)
{
printf("%d\n",dis[x[i]]+dis[y[i]]-2*dis[z[i]]);
}
}
return 0;
 } 

错误分析:开始用的链表式邻接表储存,加深搜求解的,wa了两遍,可能是指针的错误,没找到具体的地方,并且感觉时间复杂度很高,就搜了一下题解,看了一下这个tarjan算法,还是很好理解的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值