7-1 愿天下有情人都是失散多年的兄妹[PTA|思路与代码(附测试数据设坑的吐槽)]

题目

背景

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式

输入第一行给出一个正整数N(2 ≤ N ≤104),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID

其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式

对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No

输入样例

24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011

输出样例

Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No

限制条件 

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

栈限制

8192 KB

思路-美美踩坑版

先说正确的部分。

本题题设看起来很复杂,实际本质考察的是图的遍历算法。将要查询的两人分别做广度优先算法即可。查询的第一个人所有的5代内祖先都遍历一遍并储存起来,再遍历第二个人所有5代内祖先,对每个这样的祖先与前面储存的祖先进行对比,如果有一样的就输出No并停止后续的遍历,若到遍历结束都不一样,那么输出Yes。

对于数据的存储,可以选用vector,也可以选用map。本题作者选用了map,因为map能够更好更方便的通过id查找对应的内容。于是选用map来储存个人信息,可以理解成节点信息;用map储存第一个人的祖先id;储存广度优先的遍历是否访问的标志(其实可以不考虑这点,因为题目限制了血缘关系是有序的,不会重复遍历,但保险起见还是加入访问标记)。

然后就是考虑错误的部分。

既然给出每个节点的信息,那就把节点挨个存起来即可。

本来是没错的,但是问题在于有些节点的信息不是直接给出的,而是隐藏在了给出的节点中。

于是美美设定节点元素为id,gender,fatherid,motherid;

判断性别使用了A.gender==B.gender;

猛猛一顿敲代码,卡,只对了一半。

改良思路

再思考一上午无果后,查阅资料,发现了测试数据的坑点:

不给父母节点的具体信息,但是却询问父母节点。

其实父母节点确实没什么信息,在没有具体输入的时候无需作为一个节点。但是!他们是有性别的!!

所以如果不考虑父母性别,在询问两个没有给出具体信息的父母节点时,可能会出错误。比如询问A的父亲和B的父亲,但是二人只有一人有信息时,在性别判断时,一方是M,一方是空,导致认为两人性别不一样,进而给出错误结果。

因此,节点修改为id,fatherid,motherid;单独使用另一个map存储id对应的性别,如此才对。

(另外,数据还会询问所有出现过id以外的人,他们的性别确实应该认为是空,性别判断认为不一致,这个代码修改后无问题;但是若使用!=进行判断,则这个判断结果也不对)

代码

#include <iostream>
#include <string>
#include <map>
#include <queue>
using namespace std;

struct person {
	int id;
	int f_id;
	int m_id;
};

int main() {
	int n;
	cin >> n;
	map<int, person> m;
	map<int, int> have;
	map<int, string> gender;
	for (int i = 0; i < n; i++) {
		person temp;
		string s;
		cin >> temp.id >> s >> temp.f_id >> temp.m_id;
		m[temp.id] = temp;
		gender[temp.id] = s;
		if (temp.f_id != -1) {
			gender[temp.f_id] = "M";
		}
		if (temp.m_id != -1) {
			gender[temp.m_id] = "F";
		}
		have[temp.id] = 1;
	}
	int mm;
	cin >> mm;
	for (int i = 0; i < mm; i++) {
		int id1, id2;
		cin >> id1 >> id2;
		if (gender[id1] == gender[id2]) {
			cout << "Never Mind" << endl;
			continue;
		}
		map<int, int> id1_ans, id1_ans_dai;
		id1_ans.clear();
		id1_ans_dai.clear();
		queue<int> q;
		q.push(id1);
		id1_ans_dai[id1] = 0;
		while (!q.empty()) {
			int nowid = q.front();
			q.pop();
			id1_ans[nowid] = 1;
			int generation = id1_ans_dai[nowid]; // 获取当前代数
			if (have[nowid] == 1 && id1_ans.find(m[nowid].f_id) == id1_ans.end() && id1_ans_dai[nowid] < 4 && m[nowid].f_id != -1) {
				q.push(m[nowid].f_id);
				id1_ans_dai[m[nowid].f_id] = generation + 1;
			}
			if (have[nowid] == 1 && id1_ans.find(m[nowid].m_id) == id1_ans.end() && id1_ans_dai[nowid] < 4 && m[nowid].m_id != -1) {
				q.push(m[nowid].m_id);
				id1_ans_dai[m[nowid].m_id] = generation + 1;
			}
		}
		map<int, int> id2_ans_dai;
		id2_ans_dai.clear();
		queue<int> q2;
		q2.push(id2);
		id2_ans_dai[id2] = 0;
		bool flag = true;
		while (!q2.empty()) {
			int nowid = q2.front();
			q2.pop();
			if (id1_ans[nowid] == 1) {
				cout << "No" << endl;
				flag = false;
				break;
			}
			int generation = id2_ans_dai[nowid]; // 获取当前代数
			if (have[nowid] == 1 && id2_ans_dai[m[nowid].f_id] == 0 && id2_ans_dai[nowid] < 4 && m[nowid].f_id != -1) {
				q2.push(m[nowid].f_id);
				id2_ans_dai[m[nowid].f_id] = generation + 1;
			}
			if (have[nowid] == 1 && id2_ans_dai[m[nowid].m_id] == 0 && id2_ans_dai[nowid] < 4 && m[nowid].m_id != -1) {
				q2.push(m[nowid].m_id);
				id2_ans_dai[m[nowid].m_id] = generation + 1;
			}
		}
		if (flag) {
			cout << "Yes" << endl;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值