Tarjan--LCA算法的个人理解即模板

tarjan---LCA算法的步骤是(当dfs到节点u时):

  实际:  并查集+dfs

具体步骤:
1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
   1.1 tarjan之
   1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先。

举例子:

   Tarjan--LCA算法的个人理解即模板

假设遍历完10的孩子,要处理关于10的请求了
取根节点到当前正在遍历的节点的路径为关键路径,即1-3-8-10
集合的祖先便是关键路径上距离集合最近的点
比如此时:
    1,2,5,6为一个集合,祖先为1,集合中点和10的LCA为1
    3,7为一个集合,祖先为3,集合中点和10的LCA为3
    8,9,11为一个集合,祖先为8,集合中点和10的LCA为8
    10,12为一个集合,祖先为10,集合中点和10的LCA为10
你看,集合的祖先便是LCA吧,所以第3步是正确的
道理很简单,LCA(u,v)便是根至u的路径上到节点v最近的点

此段话语来自sre="http://purety.jp/akisame/oi/TJU/"

模板:

  1 #include<iostream>

  2 #include<vector>

  3 using namespace std;

  4 

  5 const int MAX=10001;

  6 int father[MAX];

  7 int rank[MAX];

  8 int indegree[MAX];//保存每个节点的入度

  9 int visit[MAX];

 10 vector<int> tree[MAX],Qes[MAX];

 11 int ancestor[MAX];

 12 

 13 

 14 void init(int n)

 15 {

 16     for(int i=1;i<=n;i++)

 17     {

 18 

 19         rank[i]=1;

 20         father[i]=i;

 21         indegree[i]=0;

 22         visit[i]=0;

 23         ancestor[i]=0;

 24         tree[i].clear();

 25         Qes[i].clear();

 26     }

 27 

 28 }

 29 

 30 int find(int n)

 31 {

 32     if(father[n]==n)

 33         return n;

 34     else

 35         father[n]=find(father[n]);

 36     return father[n];

 37 }//查找函数,并压缩路径

 38 

 39 int Union(int x,int y)

 40 {

 41     int a=find(x);

 42     int b=find(y);

 43     if(a==b)

 44         return 0;

 45     //相等的话,x向y合并

 46     else if(rank[a]<=rank[b])

 47     {

 48         father[a]=b;

 49         rank[b]+=rank[a];

 50     }

 51     else

 52     {

 53         father[b]=a;

 54         rank[a]+=rank[b];

 55     }

 56     return 1;

 57 

 58 }//合并函数,如果属于同一分支则返回0,成功合并返回1

 59 

 60 

 61 void LCA(int u)

 62 {

 63     ancestor[u]=u;

 64     int size = tree[u].size();

 65     for(int i=0;i<size;i++)

 66     {

 67         LCA(tree[u][i]);

 68         Union(u,tree[u][i]);

 69         ancestor[find(u)]=u;

 70     }

 71     visit[u]=1;

 72     size = Qes[u].size();

 73     for(int i=0;i<size;i++)

 74     {

 75         //如果已经访问了问题节点,就可以返回结果了.

 76         if(visit[Qes[u][i]]==1)

 77         {

 78             cout<<ancestor[find(Qes[u][i])]<<endl;

 79             return;

 80         }

 81     }

 82 }

 83 

 84 

 85 int main()

 86 {

 87     int cnt;

 88     int n;

 89     cin>>cnt;

 90     while(cnt--)

 91     {

 92         cin>>n;;

 93         init(n);

 94         int s,t;

 95         for(int i=1;i<n;i++)

 96         {

 97             cin>>s>>t;

 98             tree[s].push_back(t);

 99             indegree[t]++;

100         }

101         //这里可以输入多组询问

102         cin>>s>>t;

103         //相当于询问两次

104         Qes[s].push_back(t);

105         Qes[t].push_back(s);

106         for(int i=1;i<=n;i++)

107         {

108             //寻找根节点

109             if(indegree[i]==0)

110             {

111                 LCA(i);

112                 break;

113             }

114         }

115     }

116     return 0;

117 }

 

你可能感兴趣的:(tar)