题目:
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
。
所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。
思路:
1.处理字符串,标注每个维京人后裔的性别和父亲,并用set去重保存维京人的名字;
2.通过set查找和性别判断可得出第三,四条信息;
3.是否在五代以内(查询的两个人可能不是同辈)通过向上查找两个人的父结点得到。
测试点2,4错因:
姓的后缀带m或f的,均不是维京人的后裔,即便他们的儿子是维京人的后裔。
测试点3,6错因:
有一种情况是A,B的公共祖先比B的曾祖父辈分高,比A的曾祖父辈分低。而题目所要求的是公共祖先必须比A,B的曾祖父都高。
AC代码:
#include<algorithm>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
using namespace std;
const int N = 2e5+10;
int n,res,m;
map<string,string>fa;
set<string>s;
map<string,int>sex;
bool judge(string a,string b,int deep){
if(b==""){
return true;
}
int ans=1;
string k = a;
while(a!=""){
if(a==b&&(deep<=4||ans<=4)){
return false;
}
if(deep>4&&ans>4){
return true;
}
a = fa[a];
ans++;
}
return judge(k,fa[b],deep+1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
string name,surname;
cin>>name>>surname;
int len = surname.size();
if(surname[len-1]=='n'){
surname = surname.substr(0,len-4);
sex[name]=1;
fa[name]=surname;
}
else if(surname[len-1]=='r'){
surname = surname.substr(0,len-7);
sex[name]=2;
fa[name]=surname;
}
else if(surname[len-1]=='m'){
surname = surname.substr(0,len-1);
sex[name]=1;
}
else if(surname[len-1]=='f'){
surname = surname.substr(0,len-1);
sex[name]=2;
}
s.insert(name);
}
cin>>m;
for(int i=1;i<=m;i++){
string a,b,c,d;
cin>>a>>b>>c>>d;
if(s.find(a)==s.end()||s.find(c)==s.end()){
cout<<"NA"<<endl;
}
else if(sex[a]==sex[c]){
cout<<"Whatever"<<endl;
}
else if(judge(a,c,1)){
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
}
return 0;
}