`
从此醉
  • 浏览: 1040914 次
  • 性别: Icon_minigender_1
  • 来自: US
社区版块
存档分类
最新评论

poj 1986 Distance Queries

 
阅读更多

点击打开链接poj 1986


思路:LCA+Tarjan离线算法+并查集

分析:
1 LCA指的是一棵有根树上两个点的最近公共祖先,或者指的是图上两个点的最短路径。
2 这一题的边数最大40000,还有k(k<=10000)次询问,如果利用最短路的算法肯定TLE。所以这个时候我们选择LCA,假设dis[x]是x到根节点的路径长度,那么(i , j)两点的最短路径为dis[i]+dis[j]-2*dis[LCA(i , j)];LCA(i , j)指的是i,j的最近公共祖先。
3 由于输入的是一个无向图,这个时候根节点是不固定的,所以保存的时候注意保存两次。然后只要随便选取一个作为根节点进行LCA即可(习惯把1作为根节点)
4 使用的是邻阶表存储无向图,注意数组的大小,不然会RE

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 100010

int n , m , k;
int ancestor[MAXN];
int father[MAXN];
int first[MAXN];
int next[MAXN];
int dis[MAXN];
int vis[MAXN];/*标记点是否被处理过*/
vector<int>v[MAXN];
struct Edge{
   int x; 
   int y;
   int value;
   int ans;
}e[MAXN] , q[MAXN];/*保存读入的边和询问的边*/

/*初始化*/
void init(){
   for(int i = 1 ; i <= n ; i++){
      father[i] = i;
      v[i].clear();
   }
   memset(ancestor , 0 , sizeof(ancestor));
   memset(first , -1 , sizeof(first));
   memset(next , -1 , sizeof(next));
   memset(dis , 0 , sizeof(dis));
   memset(vis , 0 , sizeof(vis));
}

/*并查集的查找*/
int find_Set(int x){
   if(x != father[x])
     father[x] = find_Set(father[x]);
   return father[x];
}

/*并查集的合并*/
void union_Set(int x , int y){
    int root_x = find_Set(x);
    int root_y = find_Set(y);
    father[root_x] = root_y;
}

/*Tarjan算法*/
void LCA(int u){
    ancestor[u] = u;
    vis[u] = 1;/*标记为处理过*/
    for(int i = first[u] ; i != -1 ; i = next[i]){
       if(!vis[e[i].y]){/*找到没被处理过的点*/
           dis[e[i].y] = dis[u] + e[i].value;/*更新dis数组*/
           LCA(e[i].y);/*继续搜索子树*/
           union_Set(e[i].y , u);/*合并*/
           ancestor[find_Set(e[i].y)] = u;/*当前节点为子树的祖先*/
       }
    }
    /*处理和u 和 v[u][i]有关的询问*/
    for(int i = 0 ; i < v[u].size() ; i++){
       if(vis[v[u][i]]){
          for(int j = 0 ; j < k ; j++){
             if(q[j].x == u && q[j].y == v[u][i] || q[j].x == v[u][i] && q[j].y == u)
               q[j].ans = father[find_Set(v[u][i])];
          }
       }
    }
}

int main(){
    char c;
    while(scanf("%d%d" , &n , &m) != EOF){
        init();
        for(int i = 0 ; i < m ; i++){
           scanf("%d %d %d %c" , &e[i].x , &e[i].y , &e[i].value , &c);
           /*邻阶表存储无向图*/
           e[i+m].x = e[i].y;
           e[i+m].y = e[i].x;
           e[i+m].value = e[i].value;
        
           next[i] = first[e[i].x];
           first[e[i].x] = i;
           next[i+m] = first[e[i+m].x];
           first[e[i+m].x] = i+m;
        }
        scanf("%d" , &k);
        for(int i = 0 ; i < k ; i++){
           scanf("%d%d" , &q[i].x , &q[i].y);
           v[q[i].x].push_back(q[i].y);
           v[q[i].y].push_back(q[i].x);
        }
        LCA(1);/*1作为根节点求LCA*/
        for(int i = 0 ; i < k ; i++){
           int tmp = dis[q[i].x]+dis[q[i].y]-2*dis[q[i].ans];       
           printf("%d\n" , tmp);
        }
    }
    return 0;
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics