PTA: Icelander (25 points) (AC full score + analysis)

Posted by Xoid on Sun, 02 Feb 2020 07:50:50 +0100

L2-2 Icelanders (25 points)

In the 2018 World Cup, Iceland became famous for its 1-1 draw with Argentina. Good people found that Icelanders seem to have a "son" behind their names, so some netizens popularized science as follows:

Input example:

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
tracy tim james eric
will robin tracy tim
april mike steve bill
bob adam eric steve
tracy tim tracy tim
x man april mikes

Output example:


1. From the title, everyone's "name" is different. All of them can use "name" as identifier and map to number everyone according to the input order.
2. Remove the suffix after the Viking surname (the surname without the suffix is the name of the father)
3. At this time, we will know the number of each person's first name. Then, according to the last name of each person, we can know the number of their father's first name. (you can also use and search the set here, because each person has at most one elder, and I'm directly looping through each elder.)
4. Loop through the parents of the person to be tested, and judge whether they are the same. If they are the same, they are within five generations. (note here that in the same way, they must be higher than the great grandparents of either side. In other words, for example, if the common ancestor is the father of A and the ancestor of more than ten generations of B, it is still not possible, because it is within five generations of A; or if B is A direct relative of A, it is also possible.)
See AC code for specific explanation:

#define inf 110000
using namespace std;
map<string, int> mp;//string: name int: number
int p[inf],cnt[inf],dx[inf],dy[inf],sex[inf]; 
string ming[inf], xing[inf];  //Save everyone's first and last names 

bool judge(int x, int y)
    while(p[x] != -1){  //If x has elders, it keeps cycling up until there are no elders 
        dx[p[x]] = dx[x] + 1; //How many generations 
        if(p[x] == y) return false; //If the superior of x is equal to y, return directly and output No 
        x = p[x];
    while(p[y] != -1){
        dy[p[y]] = dy[y] + 1;
        if(cnt[p[y]] > 1){ //>1. It indicates that p[y] is also the elder of x. judge how many generations and whether it reaches five generations 
            if(dy[p[y]]>=4 && dx[p[y]] >= 4) return true;
            else return false;
        y = p[y];
    return true;

int main(){
	int n,m;
	for(int i=1; i<=n; i++){
		mp[ming[i]]=i;  //The name is unique, so change the name to number for easy processing 
		int t=xing[i].size()-1;
		if(xing[i][t]=='m'||xing[i][t]=='n') sex[i]=1;//Male (name ending with m or sson) 
		else sex[i]=-1; //female	
		//Save the last name with the suffix removed, that is, the father's first name 
		string s="";
			for(int j=0; j<t-3; j++) s+=xing[i][j];
		}else if(xing[i][t]=='r'){
			for(int j=0; j<t-6; j++) s+=xing[i][j];
	memset(p,-1,sizeof(p));//Initially - 1, no elders
	for(int i=1; i<=n; i++){
		if(mp[xing[i]]>0) p[i]=mp[xing[i]];  //p[i] indicates the number I and its father number 
	string s1,s2,s3,s4;
		int x=mp[s1],y=mp[s3];  
		if(!sex[x]||!sex[y]) cout<<"NA"<<endl;  //If sex[i] is 1, it is male, if it is - 1, it is female, if it is 0, it means there is no such person 
		else if(sex[x]==sex[y])cout<<"Whatever"<<endl;//First, we need to judge whether it exists, and then we need to judge whether it is the same sex, otherwise we can't pass some tests  
		else{ //If the opposite sex, judge whether they are close relatives 
			if(judge(x, y)) cout<<"Yes"<<endl;
			else cout<<"No"<<endl;			
	return 0;

If the reader does not understand it thoroughly, refer to the following illustration:

Graphic reference link:
Welcome to criticize and correct!!!

Published 57 original articles, won praise 4, visited 5248
Private letter follow