2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:
冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 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
分析:通过判断姓氏末位的字母来判断性别以及是否是维京人,如果是维京人还需要切割尾缀并将父亲姓名存储,之后再查询的时候,进入check函数内,枚举五代内的关系,判断是否有公共祖先~Record[A]用来存储A的性别以及父亲姓名,最后按题意输出~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <bits/stdc++.h> using namespace std; #define pis pair<int, string> int N, M; string fName, sName, temp; map<string, pis> Record; string check(string a, string b) { int cnt1 = 0, cnt2; while (a != "") { cnt2 = 0; string b2 = b; while (b2 != "") { if (a == b2 && (cnt1 < 4 || cnt2 < 4)) return "No\n"; if (cnt1 >= 4 && cnt2 >= 4) return "Yes\n"; b2 = Record[b2].second; cnt2++; } a = Record[a].second; cnt1++; } return "Yes\n"; } int main() { cin >> N; while(N--){ cin >> fName >> sName; if (sName.back() == 'n') Record[fName] = {1, sName.substr(0, sName.length() - 4)}; else if (sName.back() == 'r') Record[fName] = {0, sName.substr(0, sName.length() - 7)}; else if (sName.back() == 'm') Record[fName].first = 1; else Record[fName].first = 0; } cin >> M; while(M--){ cin >> fName >> temp >> sName >> temp; if (!Record.count(fName) || !Record.count(sName)) cout << "NA\n"; else if(Record[fName].first == Record[sName].first) cout << "Whatever\n"; else cout << check(fName, sName); } return 0; } |
❤ 点击这里 -> 订阅《PAT | 蓝桥 | LeetCode学习路径 & 刷题经验》by 柳婼