L2-016 愿天下有情人都是失散多年的兄妹
-
呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?
-
输入格式
输入第一行给出一个正整数
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
-
解题思路
-
这题主要就是求想要结婚的这两个人五服之内是否有相同的人,第一代是自己不用求,从第二代到第五代需要求解出来有哪些人,可以用BFS和DFS求出来并标记(用一个大数组使用下标标记),再利用BFS或者DFS判断另外一个人的五服内的人是否已经有存在标记了,如果有了则两人无法结婚,如果没有则可以。
-
还有就是关于父母亲的性别也必须要存储,因为后续可能会判断父亲们和母亲们之间是否可以通婚,首先就必须要判断性别是否不同。
-
对于辈分的理解,两个新人是同辈,那么他们五服中不可能存在你的父亲是他的爷爷这种情况,所以只需要第二服和第二服比较就好,相同服之间的比较(当然,我们采用标记的方法话就没必要这样做了,因为第二服和第二服之间没有相同的,第二服和其他服更不可能存在相同的,使用无需一个一个比较看有没有相同,直接看这个人是否曾经已经被标记过,这样做比较迅速)
-
-
代码
-
#include <algorithm> #include <iostream> #include <queue> #include <string.h> #include <vector> using namespace std; // 存储每个孩子的父母亲 vector<int> P[100010]; // 标记五服内出现的亲人 int BiaoJi[100010]; // 记录性别 char info[100010]; // 为什么采用两个队列呢?因为如果采用一个队列的话,无法判断这个家人到底是第几服。(当然这也不重要,主要写了就不想改了) // Q1、Q2用来记录情侣中第一个人的家人表,Q1记录第偶数服,Q2记录第奇数服 queue<int> Q1; queue<int> Q2; // Q3、Q4用来记录情侣中第二个人的家人表,Q1记录第偶数服,Q2记录第奇数服 queue<int> Q3; queue<int> Q4; // 记录第一个人的家人五服 vector<int> TX[100010]; // 记录第二个人的家人五服 vector<int> TY[100010]; int main() { void judgeMarryOrNot(); int N; cin >> N; int i; int child, father, mother; char gender; for (i = 1; i <= N; i++) { cin >> child >> gender >> father >> mother; info[child] = gender; info[father] = 'M'; info[mother] = 'F'; if (father != -1) { P[child].push_back(father); } if (mother != -1) { P[child].push_back(mother); } } // 找五服内所有家人的情况(按照第几服记录) judgeMarryOrNot(); return 0; } void judgeMarryOrNot() { int K; cin >> K; int x, y; int i; int executeX, executeY; int level = 2; int flagTime = 0; vector<int>::iterator it1; for (i = 1; i <= K; i++) { cin >> x >> y; if (info[x] == info[y]) { cout << "Never Mind" << endl; continue; } else { Q1.push(x); Q3.push(y); level = 2; flagTime = 0; // 找一个案例是否可以marry while (level <= 5) { if (level % 2 == 0) { // 找到了X全部的第level代的家人 while (Q1.size() > 0) { executeX = Q1.front(); Q1.pop(); it1 = P[executeX].begin(); while (it1 != P[executeX].end()) { Q2.push((*it1)); TX[level].push_back(*it1); BiaoJi[*it1] = 1; it1++; } } // 找到了Y的全部第level代的家人 // 并将Y的第level代的家人与X的第level代家人进行比较,若出现相同的,则不可通婚。 while (Q3.size() > 0) { executeY = Q3.front(); Q3.pop(); it1 = P[executeY].begin(); while (it1 != P[executeY].end()) { Q4.push(*it1); TY[level].push_back(*it1); it1++; } } } else if (level % 2 != 0) { while (Q2.size() > 0) { executeX = Q2.front(); Q2.pop(); it1 = P[executeX].begin(); while (it1 != P[executeX].end()) { Q1.push(*it1); TX[level].push_back(*it1); BiaoJi[*it1] = 1; it1++; } } while (Q4.size() > 0) { executeY = Q4.front(); Q4.pop(); it1 = P[executeY].begin(); while (it1 != P[executeY].end()) { Q3.push(*it1); TY[level].push_back(*it1); it1++; } } } level++; } // while(level<=5的截止) // 判断下一对情侣使用,队列必须为空 while (!Q1.empty()) Q1.pop(); while (!Q2.empty()) Q2.pop(); while (!Q3.empty()) Q3.pop(); while (!Q4.empty()) Q4.pop(); for (int k = 2; k <= 5; k++) { for (int m = 2; m <= 5; m++) { //第k行的所有数据,与另外一个人的所有行数据进行比较。 it1 = TY[k].begin(); while (it1 != TY[k].end()) { if (BiaoJi[*it1] == 1) { cout << "No" << endl; flagTime = 1; break; } it1++; } if (flagTime != 0) { break; } } if (flagTime != 0) { break; } } if (flagTime == 0) { cout << "Yes" << endl; } for (int k = 2; k <= 5; k++) { TX[k].clear(); TY[k].clear(); } // 判断下一对情侣,这个标记数组需要清0 memset(BiaoJi, 0, sizeof(BiaoJi)); } } }
- 代码比较长,挺多地方可以简化优化的,逻辑还是比较清晰。