PTA L2-016 愿天下有情人都是失散多年的兄妹

9 篇文章 0 订阅
3 篇文章 0 订阅

L2-016 愿天下有情人都是失散多年的兄妹

  • 呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

  • 输入格式

    输入第一行给出一个正整数N(2 ≤ N ≤104),随后N行,每行按以下格式给出一个人的信息:

    本人ID 性别 父亲ID 母亲ID

    其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1

    接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

    注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

  • 输出格式

    对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No

  • 输入样例

    24
    00001 M 01111 -1
    00002 F 02222 03333
    00003 M 02222 03333
    00004 F 04444 03333
    00005 M 04444 05555
    00006 F 04444 05555
    00007 F 06666 07777
    00008 M 06666 07777
    00009 M 00001 00002
    00010 M 00003 00006
    00011 F 00005 00007
    00012 F 00008 08888
    00013 F 00009 00011
    00014 M 00010 09999
    00015 M 00010 09999
    00016 M 10000 00012
    00017 F -1 00012
    00018 F 11000 00013
    00019 F 11100 00018
    00020 F 00015 11110
    00021 M 11100 00020
    00022 M 00016 -1
    00023 M 10012 00017
    00024 M 00022 10013
    9
    00021 00024
    00019 00024
    00011 00012
    00022 00018
    00001 00004
    00013 00016
    00017 00015
    00019 00021
    00010 00011
    
  • 输出样例

    Never Mind
    Yes
    Never Mind
    No
    Yes
    No
    Yes
    No
    No
    
  • 解题思路

    • 这题主要就是求想要结婚的这两个人五服之内是否有相同的人,第一代是自己不用求,从第二代到第五代需要求解出来有哪些人,可以用BFS和DFS求出来并标记(用一个大数组使用下标标记),再利用BFS或者DFS判断另外一个人的五服内的人是否已经有存在标记了,如果有了则两人无法结婚,如果没有则可以。

    • 还有就是关于父母亲的性别也必须要存储,因为后续可能会判断父亲们和母亲们之间是否可以通婚,首先就必须要判断性别是否不同。

    • 对于辈分的理解,两个新人是同辈,那么他们五服中不可能存在你的父亲是他的爷爷这种情况,所以只需要第二服和第二服比较就好,相同服之间的比较(当然,我们采用标记的方法话就没必要这样做了,因为第二服和第二服之间没有相同的,第二服和其他服更不可能存在相同的,使用无需一个一个比较看有没有相同,直接看这个人是否曾经已经被标记过,这样做比较迅速)

  • 代码

  • #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <string.h>
    #include <vector>
    using namespace std;
    // 存储每个孩子的父母亲
    vector<int> P[100010];
    // 标记五服内出现的亲人
    int BiaoJi[100010];
    // 记录性别
    char info[100010];
    
    // 为什么采用两个队列呢?因为如果采用一个队列的话,无法判断这个家人到底是第几服。(当然这也不重要,主要写了就不想改了)
    // Q1、Q2用来记录情侣中第一个人的家人表,Q1记录第偶数服,Q2记录第奇数服
    queue<int> Q1;
    queue<int> Q2;
    // Q3、Q4用来记录情侣中第二个人的家人表,Q1记录第偶数服,Q2记录第奇数服
    queue<int> Q3;
    queue<int> Q4;
    
    // 记录第一个人的家人五服
    vector<int> TX[100010];
    // 记录第二个人的家人五服
    vector<int> TY[100010];
    
    int main()
    {
        void judgeMarryOrNot();
        int N;
        cin >> N;
        int i;
        int child, father, mother;
    
        char gender;
        for (i = 1; i <= N; i++)
        {
            cin >> child >> gender >> father >> mother;
            info[child] = gender;
            info[father] = 'M';
            info[mother] = 'F';
            if (father != -1)
            {
                P[child].push_back(father);
            }
            if (mother != -1)
            {
                P[child].push_back(mother);
            }
        }
    
        // 找五服内所有家人的情况(按照第几服记录)
        judgeMarryOrNot();
        return 0;
    }
    
    void judgeMarryOrNot()
    {
        int K;
        cin >> K;
        int x, y;
        int i;
        int executeX, executeY;
        int level = 2;
        int flagTime = 0;
    
        vector<int>::iterator it1;
    
        for (i = 1; i <= K; i++)
        {
            cin >> x >> y;
    
            if (info[x] == info[y])
            {
                cout << "Never Mind" << endl;
                continue;
            }
            else
            {
                Q1.push(x);
                Q3.push(y);
                level = 2;
                flagTime = 0;
                // 找一个案例是否可以marry
                while (level <= 5)
                {
                    
                    if (level % 2 == 0)
                    {
                     
                        // 找到了X全部的第level代的家人
                        while (Q1.size() > 0)
                        {
                            executeX = Q1.front();
                            Q1.pop();
                            it1 = P[executeX].begin();
                            while (it1 != P[executeX].end())
                            {
                             
                                Q2.push((*it1));
                                TX[level].push_back(*it1);
                                BiaoJi[*it1] = 1;
                                it1++;
                            }
                        }
    
                        // 找到了Y的全部第level代的家人
                        // 并将Y的第level代的家人与X的第level代家人进行比较,若出现相同的,则不可通婚。
                        while (Q3.size() > 0)
                        {
                            executeY = Q3.front();
                            Q3.pop();
                            it1 = P[executeY].begin();
                            while (it1 != P[executeY].end())
                            {
    
                                Q4.push(*it1);
                                TY[level].push_back(*it1);
    
                                it1++;
                            }
                        }
                    }
    
                    else if (level % 2 != 0)
                    {
                        while (Q2.size() > 0)
                        {
                            executeX = Q2.front();
                            Q2.pop();
                            it1 = P[executeX].begin();
                            while (it1 != P[executeX].end())
                            {
                              
                                Q1.push(*it1);
                                TX[level].push_back(*it1);
                                BiaoJi[*it1] = 1;
                                it1++;
                            }
                        }
                
                        while (Q4.size() > 0)
                        {
                            executeY = Q4.front();
                            Q4.pop();
                            it1 = P[executeY].begin();
                            while (it1 != P[executeY].end())
                            {
                                Q3.push(*it1);
                                TY[level].push_back(*it1);
    
                                it1++;
                            }
                        }
                    }
    
                    level++;
    
                } // while(level<=5的截止)
    
                // 判断下一对情侣使用,队列必须为空
                while (!Q1.empty())
                    Q1.pop();
                while (!Q2.empty())
                    Q2.pop();
                while (!Q3.empty())
                    Q3.pop();
                while (!Q4.empty())
                    Q4.pop();
    
                for (int k = 2; k <= 5; k++)
                {
    
                    for (int m = 2; m <= 5; m++)
                    {
                        //第k行的所有数据,与另外一个人的所有行数据进行比较。
                        it1 = TY[k].begin();
                        while (it1 != TY[k].end())
                        {
                            if (BiaoJi[*it1] == 1)
                            {
                                cout << "No" << endl;
                                flagTime = 1;
                                break;
                            }
                            it1++;
                        }
                        if (flagTime != 0)
                        {
                            break;
                        }
                    }
                    if (flagTime != 0)
                    {
                        break;
                    }
                }
                if (flagTime == 0)
                {
                    cout << "Yes" << endl;
                }
    
                for (int k = 2; k <= 5; k++)
                {
                    TX[k].clear();
                    TY[k].clear();
                }
                // 判断下一对情侣,这个标记数组需要清0
                memset(BiaoJi, 0, sizeof(BiaoJi));
            }
        }
    }
    
  • 代码比较长,挺多地方可以简化优化的,逻辑还是比较清晰。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值