ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解——Lowest Common Ancestor(16进制LCA)

2021-07-15 20:57:44  阅读:225  来源: 互联网

标签:Lowest Case 16 题解 l1 tree LCA nodes 节点


Perfect binary trees are one of the coolest structures that computer scientists study. They have a lot of properties that make them very nice to work with. One of the nicest properties is that they can just be described by a single integerngiving the depth of the tree. For instance, the perfect binary tree forn= 3 looks like:

In general, a perfect binary tree with depthnwill have exactly 2n+1 – 1 nodes, and can be numbered by following the pattern seen above (there are of course other ways to number the nodes of the tree, but this is the scheme we will use in this problem).

A common question that arises when dealing with trees is the query of the lowest common ancestor (commonly called LCA) of two nodes in the tree. Formally, the LCA ofxandyis the nodezof greatest depth in the tree such thatzis an ancestor ofxandy. Nodeais an ancestor of nodecifcexists in the sub-tree rooted at nodea. Notice that 1 is trivially a common ancestor of any two nodes in the tree, but is not always thelowestcommon ancestor. For instance, the common ancestors of nodes 7 and 12 are 1 and 3, and 3 is the LCA since it is the node of greatest depth. The LCA of 2 and 13 is node 1, and the LCA of 5 and 11 is node 5. The definition of LCA guarantees that the LCA of any two nodes will always be unique.

The Problem:

Given two nodes in the tree using the numbering scheme shown above, determine the LCA of the two nodes.

完美二叉树是计算机科学家研究的最酷的结构之一。它们有很多特性,使它们非常适合使用。最好的属性之一是它们只能通过一个整数来描述树的深度。例如,forn=3 的完美二叉树看起来像:

一般来说,一个具有depthn的完美二叉树将恰好有2n+1-1个节点,并且可以按照上面看到的模式进行编号(当然还有其他方法来对树的节点进行编号,但这是我们将要使用的方案在这个问题中使用)。

处理树时出现的一个常见问题是查询树中两个节点的最低公共祖先(通常称为 LCA)。正式地,xandyi 的 LCA 是树中最大深度的节点,因此这是 xandy 的祖先。 Nodeai 是 nodecifc 的祖先,存在于以 nodea 为根的子树中。请注意,1 是树中任何两个节点的共同祖先,但并不总是最低的共同祖先。例如,节点 7 和 12 的共同祖先是 1 和 3,而 3 是 LCA,因为它是最大深度的节点。 2和13的LCA是节点1,5和11的LCA是节点5。LCA的定义保证了任意两个节点的LCA永远是唯一的。

问题:

使用上面显示的编号方案给定树中的两个节点,确定这两个节点的 LCA。

输入描述:

输入以一个正整数开始,T≤ 2∙106,表示测试用例的数量。 接下来是测试案例,每个案例都在单独的输入行上。 每个测试用例将包含两个空格分隔的整数 X 和 Y,以十六进制表示。 XandY 每个将包含来自集合 {0,1,2,3,4,5,6,7,8,9,a,b,c 的最多 1000 个字符 ,d,e,f},其中 a-frepresent 分别为 10-15。 您要确定 X 和 Y 的 LCA。 注:十六进制(基数为16)数dndn-1...d1d0通过以下公式转换为十进制数(基数为10):d0·160 +d1·161 +... +dn-1·16n-1 +dn ·16n。

输出描述:

对于每种情况,输出单行:

Case#x:y

其中xi是从1开始的案例编号,y是十六进制的LCA,没有前导0。 在每个测试用例的输出后留一个空行。

链接:https://ac.nowcoder.com/acm/contest/18480/J
来源:牛客网
 

输入

7
7 c
2 d
b 5
10 11
a020fac a030ccf
12afcdb 12afcdc
100000000 fffffffff

输出

Case #1: 3

Case #2: 1

Case #3: 5

Case #4: 8

Case #5: 501

Case #6: 255f9b

Case #7: 1

思路

众所周知,LCA需要遍历所有点确定其深度才能求出,但是在这个题里,这样做的成本非常大。因为这里每个数都是16进制数,而且还是高精数,这导致我们想要遍历整个完全树是不可能的。

因此,我苦思冥想,想到了一种可以不用转换进制也不需要遍历的方法。

我们先写一个函数比较X和Y的大小,然后将其中那个较大的数除以2,如果反复这样做,无论两个数是否在同一层,他们都会回到同一个节点(这个时候两数相等),这个节点就是他们的最大公共祖先。

代码量还是比较大的,毕竟是高精的LCA。

#include <iostream>
#include <cstring>
using namespace std;
 
char X[1001],Y[1001];
int x[1001],y[1001],l1,l2;
 
 
int power()// 比较两高精数的大小
{
    if(l1>l2) return 1;
    if(l1<l2) return -1;
    for(int i=l1;i>0;i--)
    {
        if(x[i]>y[i]) return 1;
        if(x[i]<y[i]) return -1;
    }
    return 0;
}
void change()
{
    int bo=1;
    while(bo!=0)//当X=Y时,说明此时两点都回到了他们的最大公共祖先处
    {
        bo=power();
        if(bo==1)//如果X>Y,就将X除以2
        {
            for(int i=l1;i>0;i--)
            {
                if(x[i]%2==1) x[i-1]+=16;
                x[i]/=2;
            }
            if(x[l1]==0) l1--;
        }
        if(bo==-1)//如果X<Y,就将Y除以2
        {
            for(int i=l2;i>0;i--)
            {
                if(y[i]%2==1) y[i-1]+=16;
                y[i]/=2;
            }
            if(y[l2]==0) l2--;
        }
    }
}
int main()
{
    int t;
    cin>>t;
    for(int i0=1;i0<=t;i0++)
    {
        scanf("%s%s",&X,&Y);
        l1=strlen(X);
        l2=strlen(Y);
        for(int i=0;i<l1;i++)
        {
            if(X[i]<='9'&&X[i]>='0')
            {
                x[l1-i]=X[i]-'0';
            }
            else
            {
                x[l1-i]=10+X[i]-'a';
            }
        }
        for(int i=0;i<l2;i++)
        {
            if(Y[i]<='9'&&Y[i]>='0')
            {
                y[l2-i]=Y[i]-'0';
            }
            else
            {
                y[l2-i]=10+Y[i]-'a';
            }
        }

        change();

        cout<<"Case #"<<i0<<": ";
        for(int i=l1;i>=1;i--)
        {
            if(x[i]>=10) cout<<char('a'+x[i]-10);
            else cout<<x[i];
        }
        if(i0<t) cout<<endl;
        cout<<endl;
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
    }
    return 0;
}

标签:Lowest,Case,16,题解,l1,tree,LCA,nodes,节点
来源: https://blog.csdn.net/m0_57811707/article/details/118768073

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有