三星研究院上机题(Common Ancestor in Tree)

      You are to find the closest common ancestor of two vertices in a binary tree. For example, the common ancestors of vertices 8 and 13 in the figure below are vertices 3 and 1. Among them, vertex 3 is the closest to the vertex 8 and 13. And the size of sub-tree (the number of vertices in the sub-tree) rooted by vertex 3 is 8.

      Given a binary tree and two vertices, write a program that finds the closest common ancestor and computes the size of the sub-tree rooted by the closest common ancestor. No input is given where one of the two given vertices is an ancestor of the other. For example, ‘11 and 3’ in the above tree is an invalid input. Therefore, your program does not have to consider this case.

[Constraints]

      The number of vertices are from 3 to 10000

[Input]

      You are given 10 test cases. Each test case has two lines, so the total number of lines is 20. In each test case, the first line consists of four integers, V (the number of vertices in the tree), E (the number of edges), and the indices of two vertices. E edges are listed in the next line. Each edge is represented by two vertices; the index of the parent vertex always precedes the index of the child. For example, the edge connecting vertices 5 and 8 is represented by “5 8”, not by “8 5.” There is no order in which the edges are given. Every consecutive integer in the input is separated by a space. 

Given 10 test cases,

First 4 test cases contain small number of vertices(3, 5, 7, 10 each).

Next 6 test cases contain same or greater than 50 vertices.

The indices of vertices are integers from 1 to V, and root vertex always has the index 1.

It is guaranteed that the parent vertex has smaller index than the child vertex.

In this problem, it is not important whether the child is the left child of the parent or the right child; so you can decide this arbitrarily.

[Output]

       Output 10 answers in 10 lines. Each line starts with ‘#x’ meaning the index of a test case, and writes the answer after a space. The answer has two integers: the index of the closest common ancestor and the size of the sub-tree rooted by the closest common ancestor. These two integers are separated by a space as well. 

[I/O Example]

Input (20 lines in total)

13 12 8 13 Start of the first input

1 2 1 3 2 4 3 5 3 6 4 7 7 12 5 9 5 8 6 10 6 11 11 13

10 9 1 10 Start of the second input

1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10

...

Output (10 lines in total)

#1 3 8

#2 1 10

...

解题思路:

①首先,题意就是求给出的两个节点的最近的公共父节点。且以该父节点为根,求该子树的节点个数。

②第一行数据:n,m,p,q(n个节点,m条边,求节点p和q的最小公共父节点,已及子树节点个数)

③这里比较有意思,n=m+1,且这n个节点是1~n发布的(也就是说明节点没有重复)

④错误方法:定义一个一维数组,2*i和2*i+1分别存储左右孩子,但是这样不行,首先给出的数据不是按照层次输入的边,其次如果是一颗单链树,那么会爆内存的。

④正确方法:根据约束条件,可以充分利用数字下标。定义这样一个数字a[10000][3],i表示当前该节点,a[i][0]用来存储该节点的父节点,a[i][1]和a[i][2]用来存储该节点的左右孩子节点。然后访问的时候,用个辅助数组标记即可。(源码及数据下载

#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
    //freopen("1.txt","r",stdin);
    //freopen("2.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m,p,q,x,y;
        scanf("%d%d%d%d",&n,&m,&p,&q);
        //节点数据不会大于1w,利用数组下标
        //a[][0]  存储父亲
        //a[][1]  a[][2]  分别存储左右孩子
        //这里初始值为0,说明为空
        int a[100000][3]={0};
        for(int i=0;i<m;i++){
            scanf("%d%d",&x,&y);
            //一个孩子也没有
            if(a[x][1]==0) a[x][1]=y;
            else a[x][2]=y;
            a[y][0]=x;
        }
        int judge[100000]={0};
        int ans=0;
        while(1){
            //p和q两个节点的深度不同,当其中一个退到根节点,就不用再操作了
            if(a[p][0]!=0){  //有父亲
                judge[a[p][0]]++;
                p=a[p][0];
            }
            if(a[q][0]!=0){  //有父亲
                judge[a[q][0]]++;
                q=a[q][0];
            }
            //printf("%d %d\n",p,q);
            if(judge[p]==2||judge[q]==2) {   //交叉
                if(judge[p]==2) printf("%d ",p),ans=p;
                else printf("%d ",q),ans=q;
                break;
            }else if(p==q){    //树根
                printf("%d ",p),ans=p;
                break;
            }
        }
        //队列
        int sum[10000]={0};
        int index=1;
        sum[1]=ans;
        int step=1;
        while(step<=index){
            if(a[sum[step]][1]!=0){
                sum[++index]=a[sum[step]][1];
            }
            if(a[sum[step]][2]!=0){
                sum[++index]=a[sum[step]][2];
            }
            step++;
        }
        printf(" %d\n",index);
    }
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值