PTA L2-030 冰岛人 附测试点讲解

2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:

iceland.JPG

冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir。因为冰岛人口较少,为避免近亲繁衍,本地人交往前先用个 App 查一下两人祖宗若干代有无联系。本题就请你实现这个 App 的功能。

输入格式:

输入首先在第一行给出一个正整数 N(1<N≤105),为当地人口数。随后 N 行,每行给出一个人名,格式为:名 姓(带性别后缀),两个字符串均由不超过 20 个小写的英文字母组成。维京人后裔是可以通过姓的后缀判断其性别的,其他人则是在姓的后面加 m 表示男性、f 表示女性。题目保证给出的每个维京家族的起源人都是男性。

随后一行给出正整数 M,为查询数量。随后 M 行,每行给出一对人名,格式为:名1 姓1 名2 姓2。注意:这里的是不带后缀的。四个字符串均由不超过 20 个小写的英文字母组成。

题目保证不存在两个人是同名的。

输出格式:

对每一个查询,根据结果在一行内显示以下信息:

  • 若两人为异性,且五代以内无公共祖先,则输出 Yes
  • 若两人为异性,但五代以内(不包括第五代)有公共祖先,则输出 No
  • 若两人为同性,则输出 Whatever
  • 若有一人不在名单内,则输出 NA

所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。

输入样例:

15
chris smithm
adam smithm
bob adamsson
jack chrissson
bill chrissson
mike jacksson
steve billsson
tim mikesson
april mikesdottir
eric stevesson
tracy timsdottir
james ericsson
patrick jacksson
robin patricksson
will robinsson
6
tracy tim james eric
will robin tracy tim
april mike steve bill
bob adam eric steve
tracy tim tracy tim
x man april mikes

输出样例:

Yes
No
No
Whatever
Whatever
NA

做法:

先讲一下测试点:

测试点3和6所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。比如说两个人有一个公共祖先,分别作为一方的6代,一方的4代,则这两个人不能成婚。
测试点4 是关于NA的,每个人的父亲不一定出现在表中
测试点2 只需记录维京家族的父辈,每个维京家族的起源人都是男性

接下来说做法:

1.存储所有人的性别和维京人的父亲

2.输入一对人名

        2.1根据sex值是否为0,判断其是否出现在名单中

        2.2判断是否同性

        2.3判断这对异性是否可以成婚

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_map>

using namespace std;

const int N = 200010;

unordered_map<string,string> fa;//记录维京人的父亲
unordered_map<string,int> sex;//1男 2女
unordered_map<string,int> st;//判断有无共同祖先用

bool check(string m1,string m2)
{
    st.clear();//清空
    int j = 1;
    for(string i = m1;i.size();i = fa[i],j++)//标记
        st[i] = j;
    j = 1;
    for(string i = m2;i.size();i = fa[i],j++)//判断
    {
        //cout << i << " " << st[i] << " " << j << endl;
        if(st[i]) //有相同祖先
        {
            if(st[i] >= 5 && j >= 5) return true;
            else return false;
        }
        st[i] = j;
    }
    return true;
}
int main()
{
    int n = 0;
    cin >> n;
    while(n--)
    {
        string x,m;
        cin >> m >> x;
        //记录所有人的性别
        if(x.back() == 'm') sex[m] = 1;
        else if(x.back() == 'f') sex[m] = 2;
        else if(x.back() == 'n')//记录维京人的父亲
        {
            sex[m] = 1;
            fa[m] = x.substr(0,x.size() - 4);
        }
        else
        {
            sex[m] = 2;
            fa[m] = x.substr(0,x.size() - 7);
        }
    }
    cin >> n;
    while(n--)
    {
        string x1,m1,x2,m2;
        cin >> m1 >> x1 >> m2 >> x2;
        //在哈希表中插入一个键,若不赋值,数值型默认为0,字符串则为空串
        if(!sex[m1] || !sex[m2]) puts("NA");//因为我们记录了所有人的性别,所以可以通过查询性别判断是否在名单中
        else if(sex[m1] == sex[m2]) puts("Whatever");
        else if(check(m1,m2)) puts("Yes");
        else puts("No");
    }
    return 0;
}
//测试点3和6所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。3 6 不行
//测试点4 是关于NA的
//测试点2 只需记录维京家族的父辈,每个维京家族的起源人都是男性

二刷代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_map>

using namespace std;

const int N = 100010;

unordered_map<string,int> ha;
int f[N],sex[N],st[N],idx;

int check(int p1,int p2)
{
    memset(st,0,sizeof st);
    for(int i = p1,j = 1;i;i = f[i],j++)
        st[i] = j;
    for(int i = p2,j = 1;i;i = f[i],j++)
        if(st[i])//第一个公共祖先
        {
            if(st[i] >= 5 && j >= 5) return 1;
            else return 0;
        }
    return 1;
}
void test(string name)
{
    int t = ha[name];
    cout << name << " " << t << " " << sex[t] << endl;
}
int main()
{
    int n = 0;
    cin >> n;
    for(int i = 0;i < n;i++)
    {
        string m,x;

        cin >> m >> x;
        if(!ha[m]) ha[m] = ++idx;
        int t = ha[m];
        
        if(x.back() == 'm') sex[t] = 1;
        else if(x.back() == 'f') sex[t] = 2;
        else if(x.back() == 'n')
        {
            sex[t] = 1;
            string fm = x.substr(0,x.size() - 4);
            if(!ha[fm]) ha[fm] = ++idx;
            f[t] = ha[fm];
        }
        else
        {
            sex[t] = 2;
            string fm = x.substr(0,x.size() - 7);
            if(!ha[fm]) ha[fm] = ++idx;
            f[t] = ha[fm];
        }
        //test(m);
    }
    int m = 0;
    cin >> m;
    
    while(m--)
    {
        string m1,x1,m2,x2;
        cin >> m1 >> x1 >> m2 >> x2;
        //test(m1);test(m2);
        if(!sex[ha[m1]] || !sex[ha[m2]]) puts("NA");
        else if(sex[ha[m1]] == sex[ha[m2]]) puts("Whatever");
        else
        {
            if(check(ha[m1],ha[m2])) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

结果: 

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值