zoukankan      html  css  js  c++  java
  • poj 1330 Nearest Common Ancestors LCA

    题目链接:http://poj.org/problem?id=1330

    A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: 

    In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is. 

    For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.

    Write a program that finds the nearest common ancestor of two distinct nodes in a tree. 

    题意描述:在一个DAG中,定义节点u是节点v的祖先:节点u是树根到节点v的路径上的一个节点。 给出一些节点之间的关系,求出两个节点的最近公共祖先。

    算法分析:最近公共祖先(LCA)的入门题。

    最近公共祖先算法的大致思路:

    1:求出每个节点的2^k(0<=k<max_log_n)的祖先节点。节点u的2^0(第一代)祖先节点就是u的父亲节点,那么我们可以得到u的第一代、第二代、第四代、第八代...祖先节点。

    2:把节点u和v深度大的节点根据1中的算法思想移到和深度小的节点同一深度(树根深度为0,树根的儿子节点深度为1),然后再一起往上移,即可求出LCA。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<vector>
     8 #define inf 0x7fffffff
     9 using namespace std;
    10 const int maxn=10000+10;
    11 const int max_log_maxn=14;
    12 
    13 int n,A,B,root;
    14 vector<int> G[maxn];
    15 int father[max_log_maxn][maxn],d[maxn];
    16 
    17 void dfs(int u,int p,int depth)
    18 {
    19     father[0][u]=p;
    20     d[u]=depth;
    21     int num=G[u].size();
    22     for (int i=0 ;i<num ;i++)
    23     {
    24         int v=G[u][i];
    25         if (v != father[0][u]) dfs(v,u,depth+1);
    26     }
    27 }
    28 
    29 void init()
    30 {
    31     dfs(root,-1,0);
    32     for (int k=0 ;k+1<max_log_maxn ;k++)
    33     {
    34         for (int i=1 ;i<=n ;i++)
    35         {
    36             if (father[k][i]<0) father[k+1][i]=-1;
    37             else father[k+1][i]=father[k][father[k][i] ];
    38         }
    39     }
    40 }
    41 
    42 int LCA()
    43 {
    44     if (d[A]<d[B]) swap(A,B);
    45     for (int k=0 ;k<max_log_maxn ;k++)
    46     {
    47         if ((d[A]-d[B])>>k & 1)
    48         {
    49             A=father[k][A];
    50         }
    51     }
    52     if (A==B) return A;
    53     for (int k=max_log_maxn-1 ;k>=0 ;k--)
    54     {
    55         if (father[k][A] != father[k][B])
    56         {
    57             A=father[k][A];
    58             B=father[k][B];
    59         }
    60     }
    61     return father[0][A];
    62 }
    63 
    64 int main()
    65 {
    66     int t;
    67     scanf("%d",&t);
    68     while (t--)
    69     {
    70         scanf("%d",&n);
    71         for (int i=0 ;i<=n ;i++) G[i].clear();
    72         for (int i=0 ;i<max_log_maxn ;i++)
    73         {
    74             for (int j=0 ;j<maxn ;j++)
    75                 father[i][j]=-1;
    76         }
    77         int a,b;
    78         int vis[maxn];
    79         memset(vis,0,sizeof(vis));
    80         for (int i=0 ;i<n-1 ;i++)
    81         {
    82             scanf("%d%d",&a,&b);
    83             G[a].push_back(b);
    84             vis[b]=1;
    85         }
    86         scanf("%d%d",&A,&B);
    87         for (int i=1 ;i<=n ;i++) if (!vis[i]) {root=i;break; }
    88         init();
    89         printf("%d
    ",LCA());
    90     }
    91     return 0;
    92 }
  • 相关阅读:
    oracle创建函数和调用存储过程和调用函数的例子(区别)
    oracle存储过程的创建和使用
    oracle恢复已删除数据
    存储管理工具StorageExplorer的基本使用
    Azure CLI对ASM,ARM资源的基本操作
    Windows系统安装Azure CLI
    Azure Powershell对ASM资源的基本操作
    Azure Powershell对ARM资源的基本操作
    安装Windows Azure Powershell
    Linux虚拟机之间实现密钥登陆
  • 原文地址:https://www.cnblogs.com/huangxf/p/4305260.html
Copyright © 2011-2022 走看看