Bootstrap

L2-030 冰岛人 - java

L2-030 冰岛人


时间限制
400 ms
内存限制
64 MB


题目描述:

2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:
请添加图片描述
冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir。因为冰岛人口较少,为避免近亲繁衍,本地人交往前先用个 App 查一下两人祖宗若干代有无联系。本题就请你实现这个 App 的功能。

输入格式:
输入首先在第一行给出一个正整数 N ( 1 < N ≤ 1 0 5 ) N(1 < N \le 10^{5} ) N1<N105,为当地人口数。随后 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


给定n个人的姓名,求m组人名的关系。

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

孩子的姓等于父亲的名加后缀。


emmmmmmm

在输入n个人的姓名时,通过姓的性别后缀来判断是否为 维京人后裔

  • 后缀为ssonsdottir,则为维京人后裔
  • 后缀为 mf,则为其他人
    ssonm,表示男
    sdottirf,表示女

然后用名来存储,每个人的性别与姓


然后再判断m组人名的时候
先判断两个人是否都出现在名单中

  • 未出现, 则输出NA
  • 出现,则判断两个人性别是否相同
    • 相同, 则输出 Whatever
      • 最后判断两个人是否五代内有公共祖先
        • 出现,则输出No
        • 未出现, 则输出Yes

如何判断两个人是否五代以内呢?

  • 因为孩子的姓等于父亲的名
  • 所以可以通过判断当前这个人的姓往上找祖先

注: 本题我java过不去,最后一个数据怎么都是TLE


import java.io.*;
import java.util.*;

public class Main
{
	static TreeMap<String, edge> tr = new TreeMap<String, edge>();

	static String check(String a, String b)
	{
		int cnt1 = 0; // a的第几代祖先了
		while (!a.equals("")) // 如果a还有祖先
		{
			int cnt2 = 0; // b的第几代祖先了
			String c = b; // b的第0代祖先为自己
			while (!c.equals("")) // 如果b还有祖先
			{
			    // 如果a的祖先与b的祖先相同,并且在5代以内
				if (a.equals(c) && (cnt1 < 4 || cnt2 < 4)) return "No";
				// 如果当前判断的a祖先与b祖先都超过了5代
				if (cnt1 >= 4 && cnt2 >= 4) return "Yes";
				c = tr.get(c).fname; // 替换b的祖先
				cnt2++; // b的祖先代数增加
			}
			a = tr.get(a).fname; // 替换a的祖先
			cnt1++; // a的祖先代数增加
		}
		return "Yes";
	}

	public static void main(String[] args)
	{
		int n = sc.nextInt();
		while (n-- > 0)
		{
			String sname = sc.next(); // 名
			String fname = sc.next(); // 姓

            // 姓的长度
			int len = fname.length();
			// 姓中的带性别后缀
			char op = fname.charAt(len - 1);
			
			// 如果是维京人后裔的男
			if (op == 'n') tr.put(sname, new edge(1, fname.substring(0, len - 4)));
			// 如果是维京人后裔的女
			else if (op == 'r') tr.put(sname, new edge(0, fname.substring(0, len - 7)));
			// 如果是其他人的男
			else if (op == 'm') tr.put(sname, new edge(1, ""));
			// 如果是其他人的女
			else if (op == 'f') tr.put(sname, new edge(0, ""));
		}

		int m = sc.nextInt();
		while (m-- > 0)
		{
			String sname1 = sc.next();
			String fname1 = sc.next();
			String sname2 = sc.next();
			String fname2 = sc.next();
			// 判断两个人是否有一个人不在名单内
			if (!tr.containsKey(sname1) || !tr.containsKey(sname2)) out.println("NA");
			// 判断两个人是否同性
			else if (tr.get(sname1).sex == tr.get(sname2).sex) out.println("Whatever");
			else out.println(check(sname1, sname2));
		}

		out.flush();
		out.close();
	}

	static class edge
	{
		int sex; // 性别
		String fname; // 姓(也就是父亲的名)

		public edge(int sex, String fname)
		{
			this.sex = sex;
			this.fname = fname;
		}
	}

	static Scanner sc = new Scanner(System.in);
	static PrintWriter out = new PrintWriter(System.out);

}

c++

#include <iostream>
#include <unordered_map>

#define PIS pair<int, string>

using namespace std;

const int N = 1e5 + 10;
unordered_map<string, PIS> mp;

string check(string a, string b)
{
    int cnt1 = 0;
    while(a != "")
    {
        int cnt2 = 0;
        string c = b;
        while(c != "")
        {
            if(a == c && (cnt1 < 4 || cnt2 < 4)) return "No";
            if(cnt1 >= 4 && cnt2 >= 4) return "Yes";
            c = mp[c].second;
            cnt2 ++;
        }
        a = mp[a].second;
        cnt1 ++;
    }
    return "Yes";
}

int main()
{
    int n; cin >> n;
    while(n -- > 0)
    {
        string a, b; cin >> a >> b;
        if(b.back() == 'n') mp[a] = {1, b.substr(0, b.size() - 4)};
        else if(b.back() == 'r') mp[a] = {0, b.substr(0, b.size() - 7)};
        else if(b.back() == 'm') mp[a] = {1, ""};
        else if(b.back() == 'f') mp[a] = {0, ""};
    }
    
    int m; cin >> m;
    while(m -- > 0)
    {
        string a, b, c, d; cin >> a >> b >> c >> d;
        if(!mp.count(a) || !mp.count(c)) cout << "NA\n";
        else if(mp[a].first == mp[c].first) cout << "Whatever\n";
        else cout << check(a, c) << "\n";
    }
    
    return 0;
}

TreeMap
TreeMap


如果有说错的 或者 不懂的 尽管提 嘻嘻

一起进步!!!


闪现

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;