欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

L2-030 冰岛人 (25分)

程序员文章站 2022-06-08 12:05:57
...

2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:
L2-030 冰岛人 (25分)
冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir。因为冰岛人口较少,为避免近亲繁衍,本地人交往前先用个 App 查一下两人祖宗若干代有无联系。本题就请你实现这个 App 的功能。
输入格式:
输入首先在第一行给出一个正整数 N(1<N≤10​5​​),为当地人口数。随后 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
写这道题的过程还是蛮艰辛的,经历了几天的奋斗终于把所以的测试点都搞定了,还要多谢博客园的一位研究生大佬的帮助,没有他我还不知道要花多长的时间才能搞定

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <time.h>
typedef struct Node{
    char first_name[21] , last_name[21];
    int sex , pos;
    struct Node *pre;
}node;
node str[100005] , p , q;
typedef struct Pnode{
    char str[21];
    int pos;
    struct Pnode *next;
}pnode;
pnode *array[26];
int n , m , i , pos[100005] , k , pos_p , pos_q;
void Function()//存入数据
{
    char ch = str[i].first_name[0];
    pnode *q = (pnode*)malloc(sizeof(pnode));
    strcpy(q -> str , str[i].first_name);
    q -> pos = i;
    q -> next = array[ch - 'a'];
    array[ch - 'a'] = q;
}
int function(char *q)//查找信息
{
    char ch = q[0];
    pnode *p = array[ch - 'a'];
    while(p)
    {
        if(strcmp(p -> str , q) == 0) return p -> pos;//找到则返回该人的位置,否则返回0
        p = p -> next;
    }
    return 0;
}
void Assignment()
{
    scanf("%d",&n);
    for(i = 1 ; i <= n ; i ++)
    {
        scanf("%s%s",str[i].first_name , str[i].last_name);
        str[i].pos = i;
        str[i].pre = NULL;
        int len = strlen(str[i].last_name) , flag = 0;
        switch(str[i].last_name[len - 1])
        {
            case 'm':str[i].sex = 1;str[i].last_name[len - 1] = '\0';break;
            case 'f':str[i].sex = 0;str[i].last_name[len - 1] = '\0';break;
            case 'n':str[i].sex = 1;str[i].last_name[len - 4] = '\0';flag ++;break;
            case 'r':str[i].sex = 0;str[i].last_name[len - 7] = '\0';flag ++;break;
        }
        Function();//存放当前的人物信息
        if(flag)
        {
            int cnnt = function(str[i].last_name);//查找当前人物的父亲或母亲
            if(cnnt) str[i].pre = &str[cnnt];//i记录其祖先的位置
            else pos[k ++] = i;//如果i之前没有输入i的父母或i就是第一代祖先就将i记录下来
        }
    }
    for(i = 0 ; i < k ; i ++)//再次查找,解决后输入父母的问题
    {
        int temp = pos[i];
        int cnnt = function(str[temp].last_name);
        if(cnnt) str[temp].pre = &str[cnnt];
    }
    memset(pos , 0 , sizeof(pos));
}
int Final_treatment()
{
    k = 0;
    int len_p[100005] = {0} , len_q[100005] = {0} , flag_p = pos_p , flag_q = pos_q , Final_flag = 0;
    pos[flag_p] = pos_p;//先从p查找一直到起源人,以pos_p标记每一代查找到的祖先,len_p记录每一代祖先到P的高度
    while(str[flag_p].pre)
    {
        flag_p = str[flag_p].pre -> pos;
        len_p[flag_p] = ++ k;
        pos[flag_p] = pos_p;
    }
    k = 0;
    if(pos[flag_q] == pos_p) return 0;//如果q是p的祖先直接返回0
    while(Final_flag == 0 && str[flag_q].pre)
    {
        flag_q = str[flag_q].pre -> pos;//查找q的每一代祖先
        len_q[flag_q] = ++ k;//标记每一代祖先到q的高度
        if(pos[flag_q] == pos_p) Final_flag ++;//如果找到公共祖先就标记跳出
    }
    if(!Final_flag) return 1;//没有公共祖先就返回1
    if(len_p[flag_q] > 3 && len_q[flag_q] > 3) return 1;//有公共祖先且到q,p的高度均大于3也返回1
    return 0;//五代以内有公共祖先返回0
}
void Scend_treatment()
{
    scanf("%d",&m);
    for(i = 0 ; i < m ; i ++)
    {
        scanf("%s%s%s%s",p.first_name , p.last_name , q.first_name , q.last_name);
        //查找p,q位置
        pos_p = function(p.first_name);
        pos_q = function(q.first_name);
        if(pos_p && pos_q)
        {
            if(str[pos_p].sex == str[pos_q].sex) printf("Whatever\n");
            else
            {
                int cnnt = Final_treatment();
                if(cnnt) printf("Yes\n");
                else printf("No\n");
            }
        }
        else printf("NA\n");
    }
}
int main()
{
    Assignment();
    Scend_treatment();
    return 0;
}

L2-030 冰岛人 (25分)
这道题也算是一个分水岭吧!我将开始挑战L3的题目了,开始学图论了