How far away ?

hdu2586:http://acm.hdu.edu.cn/showproblem.php?pid=2586

题意:给你一棵树,然后询问任意两点之间的距离。

题解1:直接用spfa,求最短路,因为只有40000-1条边,200个查询,所以应该可以过。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<queue>
 6 #define inf 2000000000
 7 using namespace std;
 8 const int N=1e4*4+5;
 9 long long dist[N],n,m;
10 bool vis[N];
11 struct Node{
12   int v;
13   int next;
14   int w;
15 }edge[N*4];
16 int head[N],cnt;
17 void init(){
18   memset(head,-1,sizeof(head));
19   cnt=0;
20 }
21 void add(int u,int v,int w){
22      edge[cnt].v=v;
23      edge[cnt].next=head[u];
24      edge[cnt].w=w;
25      head[u]=cnt++;
26      edge[cnt].v=u;
27      edge[cnt].next=head[v];
28      edge[cnt].w=w;
29      head[v]=cnt++;
30 }
31 
32 long long spfa(int u,int ed){
33   for(int i=1;i<=n;i++){
34     dist[i]=inf;
35     vis[i]=0;
36   }
37   queue<int>Q;
38   dist[u]=0;
39   vis[u]=1;
40   Q.push(u);
41   while(!Q.empty()){
42       int d=Q.front();
43       Q.pop();
44       vis[d]=0;
45       for(int i=head[d];i!=-1;i=edge[i].next){
46          int v=edge[i].v;
47          if(dist[v]>dist[d]+edge[i].w){
48             dist[v]=dist[d]+edge[i].w;
49             if(!vis[v]){
50                 Q.push(v);
51                 vis[v]=1;
52             }
53          }
54       }
55   }
56   return dist[ed];
57 }
58 int cas,t1,t2,t3;
59 int main(){
60     scanf("%d",&cas);
61     while(cas--){
62         scanf("%d%d",&n,&m);
63         init();
64         for(int i=1;i<n;i++){
65             scanf("%d%d%d",&t1,&t2,&t3);
66             add(t1,t2,t3);
67         }
68         for(int i=1;i<=m;i++){
69             scanf("%d%d",&t1,&t2);
70             printf("%I64d\n",spfa(t1,t2));
71         }
72     }
73 }
View Code

题解2:LCA来搞,记录每个点到根节点的距离,然后找到最近公共祖先,最后的结果就是dist[u]+dist[v]-2*dist[LCA(u,v)];其中还有很多问题要考虑,细节问题,

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 using namespace std;
  6 #define N 40001
  7 int n,m;
  8 int fa[N],indegree[N];//并查集和统计度数
  9 
 10 int vis[N],ances[N];//DFS过程中标记是否访问以及记录祖先
 11 
 12 int head[N],cnt,sum[N];;//记录查询的变量,sum[i],表示第3个点查询的次数,可以解决重复查询同一个值
 13 
 14 int ans[N];//记录最终查询结果
 15 int head2[N],cnt2;//记录原来树的变量
 16 int dist[N];//记录到根节点的距离
 17 struct Node{
 18    int v;
 19    int next;
 20    int id;
 21 }edge[N*4],hash[N*4];//分贝存查询和原树
 22 
 23 void init1(){
 24   memset(head,-1,sizeof(head));
 25   memset(ans,-1,sizeof(ans));
 26   memset(head2,-1,sizeof(head2));
 27   memset(sum,0,sizeof(sum));
 28   cnt=cnt2=0;
 29 }
 30 void add(int u,int v,int w){
 31     edge[cnt].v=v;
 32     edge[cnt].id=w;
 33     edge[cnt].next=head[u];
 34     head[u]=cnt++;
 35     edge[cnt].v=u;
 36     edge[cnt].id=w;
 37     edge[cnt].next=head[v];
 38     head[v]=cnt++;
 39 }
 40 void add1(int u,int v,int w){
 41     hash[cnt2].v=v;
 42     hash[cnt2].id=w;
 43     hash[cnt2].next=head2[u];
 44     head2[u]=cnt2++;
 45 }
 46 void init2(){
 47     for(int i=0;i<=n;i++){
 48         fa[i]=i;
 49         indegree[i]=0;
 50         vis[i]=0;
 51         ances[i]=0;
 52     }
 53 }
 54 int find(int x){
 55    int s;
 56    for(s=x;s!=fa[s];s=fa[s]);
 57    while(s!=x){
 58      int temp=fa[x];
 59      fa[x]=s;
 60      x=temp;
 61    }
 62    return s;
 63 }
 64 void unio(int x,int y){
 65     int fx=find(x),fy=find(y);
 66     if(fx==fy) return ;
 67      fa[fy]=fx;
 68 }
 69 void Tarjan(int u,int len){
 70     ances[u]=u;
 71     dist[u]=len;
 72     for(int i=head2[u];i!=-1;i=hash[i].next){
 73         int v=hash[i].v;
 74         int w=hash[i].id;
 75         Tarjan(v,len+w);
 76         unio(u,v);
 77         ances[find(u)]=u;
 78     }
 79     vis[u]=1;
 80     for(int i=head[u];i!=-1;i=edge[i].next){
 81         int v=edge[i].v;
 82         if(vis[v]==1&&sum[v]>0){
 83             ans[edge[i].id]=dist[u]+dist[v]-2*dist[ances[find(v)]];
 84             sum[v]--;
 85         }
 86     }
 87 }
 88 int main(){
 89     int t;
 90     int i,j;
 91     scanf("%d",&t);
 92     while(t--){
 93         scanf("%d",&n);
 94         scanf("%d",&m);//询问的次数
 95         init1();init2();
 96         int s,d,l;
 97         for(i=1;i<=n-1;i++){
 98             scanf("%d%d%d",&s,&d,&l);
 99             if(s>d)swap(s,d);//保证是建立是一棵树
100             add1(s,d,l);
101             indegree[d]++;
102         }
103           for(int i=1;i<=m;i++){
104                 scanf("%d%d",&s,&d);
105                  sum[d]++;
106                  sum[s]++;
107                  add(s,d,i);
108              }
109         for(j=1;j<=n;j++){
110             if(indegree[j]==0){
111                 Tarjan(j,0);
112                 break;
113             }
114         }
115        for(int i=1;i<=m;i++){
116         printf("%d\n",ans[i]);
117       }
118     }
119     return 0;
120 }
View Code

 

posted on 2014-07-27 15:21  天依蓝  阅读(189)  评论(0编辑  收藏  举报

导航