LCA(最近公共祖先)tarjan算法学习笔记

来源:互联网 发布:mac照片icloud 编辑:程序博客网 时间:2024/06/11 10:36

给一棵树,问两个节点的最近公共祖先是什么。

    首先要说明的是,tarjan算法是离线的,它一次性读入所有的询问,而且不一定按照读入顺序来处理,但这也是算法的精妙之处;这个算法基于dfs和并查集。

      每当处理好一颗子树的时候,我们就把他们归并到一个集合里,显然如果询问的两个点是在一颗子树里,那么他们的LCA就是这个子树的根,如果不是的话,就可能是这颗子树的根的根(的根...的根

    存储询问也很特别,例如询问a,b,算法把a,b  b,a都存下来,保证完整性

    接下来我就具体的一棵树来讲解:

     


    从1开始搜索,我们假设路径为1-2-5-9,接着先判断,在9这个子树(其实是一个叶子)有没有要问的,显然不会有,因为除了这里处理完了,其他地方都没处理,接着回溯上来以后,合并5,9,递归到10,假如这时候询问9,10 或者 10,9 那么答案就已经计算出来了,就是5,也就是(5,9,10)这颗子树的根,如果没有询问,那么以后涉及到这颗子树的某个点的话,它们的LCA必定不是5,一定是5的祖先(的祖先....的祖先),所以当从5回溯到2的时候,我们就要把5和2合并起来,然后把5的祖先修改成2然后再去递归6,其他过程也就类似了。


附:POJ1330代码:点击打开链接

              

                   #include<stdio.h>                                                          #include<string.h>                                                                            #include<iostream>                                                                            #include<algorithm>                                                                           #include<vector>                                                                                                                                                                            using namespace std;                                                                                                                                                                        const int maxn=10005;                                                                         vector<int>tree[maxn],que[maxn];//树和询问                                                    bool vis[maxn];                                                                               int father[maxn];                                                                             int ancestor[maxn];                                                                           int rank[maxn];                                                                               int in[maxn];//入度,找根                                                                     int n;                                                                                                                                                                                      void init()                                                                                   {                                                                                                 for (int i=1;i<=n;i++)                                                                        {                                                                                                 rank[i]=1;                                                                                    father[i]=i;                                                                                  in[i]=0;                                                                                      vis[i]=0;                                                                                     ancestor[i]=0;                                                                                que[i].clear();                                                                               tree[i].clear();                                                                          }                                                                                         }                                                                                                                                                                                           int find(int x)                                                                               {                                                                                                 if (x==father[x])                                                                                 return x;                                                                                 father[x]=find(father[x]);                                                                    return father[x];                                                                         }                                                                                                                                                                                           void Union(int x,int y)                                                                       {                                                                                                 int a=find(x);                                                                                int b=find(y);                                                                                if (a!=b)                                                                                     {                                                                                                 if (rank[a]<=rank[b]) //合并的时候按深度浅的向深的合并                                                                        {                                                                                                 father[a]=b;                                                                                  rank[b]+=rank[a];                                                                         }                                                                                             else                                                                                          {                                                                                                 father[b]=a;                                                                                  rank[a]+=rank[b];                                                                         }                                                                                         }                                                                                         }                                                                                                                                                                                           void LCA(int root)                                                                            {                                                                                                 ancestor[root]=root;                                                                          int size=tree[root].size();                                                                   for (int i=0;i<size;i++)                                                                      {                                                                                                 LCA(tree[root][i]);                                                                           Union(root,tree[root][i]);                                                                    //printf("%d %d %d %d\n",root,tree[root][i],find(root),ancestor[find(root)]);                   ancestor[find(root)]=root;                                                     }                                                                                             vis[root]=1;                                                                                  size=que[root].size();                                                                        for (int i=0;i<size;i++)                                                                      {                                                                                                 if (vis[que[root][i]])                                                                        {                                                                                                 printf("%d\n",ancestor[find(que[root][i])]);                                                                             }                                                                                                                                                                                       }                                                                                         }                                                                                                                                                                                           int main()                                                                                    {                                                                                                 int t;                                                                                        scanf("%d",&t);                                                                               while (t--)                                                                                   {                                                                                                 int x,y;                                                                                      scanf("%d",&n);                                                                               init();                                                                                       for (int i=0;i<n-1;i++)                                                                       {                                                                                                 scanf("%d%d",&x,&y);                                                                          tree[x].push_back(y);                                                                         in[y]++;                                                                                  }                                                                                             scanf("%d%d",&x,&y);                                                                          que[x].push_back(y);                                                                          que[y].push_back(x);                                                                          for (int i=1;i<=n;i++)                                                                        {                                                                                                 if (in[i]==0)                                                                                 {                                                                                                 LCA(i);                                                                                       break;                                                                                    }                                                                                         }                                                                                         }                                                                                             return 0;                                                                                 }                                                                                             


0 0
原创粉丝点击