【链表】找出直系亲属

题目描述

    如果A,B是C的父母亲,则A,B是C的parent,C是A,B的child,如果A,B是C的(外)祖父,祖母,则A,B是C的grandparent,C是A,B的grandchild,如果A,B是C的(外)曾祖父,曾祖母,则A,B是C的great-grandparent,C是A,B的great-grandchild,之后再多一辈,则在关系上加一个great-。

输入描述:

    输入包含多组测试用例,每组用例首先包含2个整数n(0<=n<=26)和m(0<m<50), 分别表示有n个亲属关系和m个问题, 然后接下来是n行的形式如ABC的字符串,表示A的父母亲分别是B和C,如果A的父母亲信息不全,则用-代替,例如A-C,再然后是m行形式如FA的字符串,表示询问F和A的关系。
    

输出描述:

    如果询问的2个人是直系亲属,请按题目描述输出2者的关系,如果没有直系关系,请输出-。
    具体含义和输出格式参见样例.

示例1

输入

复制

3 2
ABC
CDE
EFG
FA
BE

输出

复制

great-grandparent
-

题目连接:https://www.nowcoder.com/practice/2c958d09d29f46798696f15ae7c9703b?tpId=40&tqId=21453&rp=1&ru=%2Fta%2Fkaoyan&qru=%2Fta%2Fkaoyan%2Fquestion-ranking&tab=answerKey

其实本质相当于倒过来的二叉树

比如题目中的例子

A是BC的孩子,那么应该建立由B向A的链表和由C向A的链表,这样的目的是从任何一个节点向下遍历方向是唯一的,容易确定先后顺序

比如我想知道G和C是不是直系亲属,那么从G遍历下来的路径是GECA,这里面包含了C,所以G是C的爷爷(因为隔了两代)

如果判断G和D是不是直系亲属,从G向下遍历是GECA,从D遍历下来时DCA,注意,虽然有交集CA,但由于G的遍历中不含有D,D的遍历中不含有G,所以两者不是直接亲属

基于以上的思想,我们可以开一个map分别记录每一个人的指针,之后开一个vector,记录每人向下遍历的路径。

之后比如想知道B和G的关系,首先根据map找到B指针,根据指针找到vector中B的遍历路径,查找是否有G。如果有的话,证明B是G的前辈,按照代数输出parent即可。

如果没有,则反过来根据map找到G的指针,根据指针找到vector中G的遍历路径,查找是否有B,如果有证明B是G的孩子,根据代数输出child即可。

若也没有,则为-,即不是直系亲属

总结:是一道链表的好题目

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#include <sstream>
#include<map>
using namespace std;
struct data{
    char id;
    data* child;
    data(char id):id(id),child(NULL){}
};
int find(vector<char> v,char text){
    for(int i=0;i<v.size();i++){
        if(v[i]==text){
            return i;
        }
    }
    return -1;
}
map<char,data*>mp;
int main(){
    int num,ques;
    cin>>num>>ques;
    mp.clear();
    for(char i='A';i<='Z';i++)
        mp[i]=NULL;
    while(num--){
        char a[3];
        cin>>a;
        data* p1=mp[a[1]];
        data* p2=mp[a[2]];
        //如果map中没有这个人的指针位置,则需要存入map
        //如果已经有了,即p1!=NULL时,表明之前已经存入map了,不用再次存储
        if(p1==NULL){
            p1=new data(a[1]);
            mp[a[1]]=p1;
        }
        if(p2==NULL){
            p2=new data(a[2]);
            mp[a[2]]=p2;
        }
        data* p0=mp[a[0]];
        if(p0==NULL){
            p0=new data(a[0]);
            mp[a[0]]=p0;
        }
        //如果缺少父母信息,则不存入数据
        if(a[1]!='-')
            p1->child=p0;
        if(a[2]!='-')
            p2->child=p0;
    }
    vector<char>v[26];
    //记载每一个人的遍历路径,比如vector[0]表明A从上到下的遍历路径
    for(int i=0;i<26;i++){
        data* now=mp['A'+i];
        while(now!=NULL){
            v[i].push_back(now->id);
            now=now->child;
        }
    }
    while(ques--){
        char temp[2];
        cin>>temp;
        char s1=temp[0];
        char s2=temp[1];
        int ans=find(v[s1-'A'],s2);
        if(ans==-1){//从s1到s2找不到时,倒过来找试试,因为s1不是s2的前辈时,有可能s1是s2的后辈
            ans=find(v[s2-'A'],s1);
            if(ans==-1){//既不是前辈也不是后辈,则不是直系亲属
                cout<<"-"<<endl;
            }
            else if(ans==1)
                cout<<"child"<<endl;
            else if(ans==2)
                cout<<"grandchild"<<endl;
            else {
                for(int i=1;i<=ans-2;i++)
                    cout<<"great-";
                cout<<"grandchild"<<endl;
            }
        }
        else{
            if(ans==1)
                cout<<"parent"<<endl;
            else if(ans==2)
                cout<<"grandparent"<<endl;
            else{
                for(int i=1;i<=ans-2;i++)
                    cout<<"great-";
                cout<<"grandparent"<<endl;
            }
            
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值