洛谷-P2814 家谱
题目背景
现代的人对于本家族血统越来越感兴趣。
题目描述
给出充足的父子关系,请你编写程序找到某个人的最早的祖先。
输入格式
输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系中父亲只有一行,儿子可能有若干行,用 #name 的形式描写一组父子关系中的父亲的名字,用 +name 的形式描写一组父子关系中的儿子的名字;接下来用 ?name 的形式表示要求该人的最早的祖先;最后用单独的一个 $ 表示文件结束。
输出格式
按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式为:本人的名字 + 一个空格 + 祖先的名字 + 回车。
输入输出样例
输入 #1 |
输出 #1 |
#George +Rodney #Arthur +Gareth +Walter #Gareth +Edward ?Edward ?Walter ?Rodney ?Arthur $ |
Edward Arthur Walter Arthur Rodney George Arthur Arthur
|
说明/提示
规定每个人的名字都有且只有 6 个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有1e3 组父子关系,总人数最多可能达到 5e4人,家谱中的记载不超过 30 代。
题目分析
1 #为父亲,+为#的儿子。
2 也就是说,+对应的节点内要存储#的位置,此处分为两种情况:
- #是新的,在上面案例中没有。此时用一个新的节点放#就可以,之后的+元素直接存储这个新位置的信息。
- #是旧的,在上面案例中出现过。那么之后的+元素需要存储它第一次位置信息。
3 把?单独存到一个新的数组中,然后挨个去遍历它在集合中的位置,再通过集合去找它的祖宗输出即可。
可行代码
#include <iostream> #include <string.h> using namespace std; // const int MAX = 5e4 + 5; const int MAX = 20; struct { char name[10]; int parent; } family[MAX]; // 个人信息结构体,集合用这个数组表示 void init(int len) { for (int i = 0; i < len; i++) family[i].parent = i; return; } int find(int aim) { if (family[aim].parent != aim) aim = find(family[aim].parent); return aim; } void merge(int a, int b) { a = find(a), b = find(b); if (a != b) family[b].parent = a; return; } int search(char *str, int len) { char *p = str; p++; int i; for (i = 0; i < len; i++) { char *q = family[i + 1].name; q++;// 输入时输入了前缀+#?,这里排除 if (strcmp(p, q) == 0) break; } if (i == len) return -1; return i + 1; } int main() { int cnt = 1, count = 0; int FindParent[MAX]; init(MAX); while (1) { // 输入数组,并建立集合 int TempParent; cin >> family[cnt].name; if (*(family[cnt].name) == '$') break; else if (*(family[cnt].name) == '#') { int loc = search(family[cnt].name, cnt); // 判断之前是否出现过 if (loc != -1 && loc != cnt) { TempParent = loc; continue; } family[cnt].parent = cnt; TempParent = cnt;// 后面的+元素,都是它的孩子 } else if (*(family[cnt].name) == '+') { family[cnt].parent = TempParent; int loc = search(family[cnt].name, cnt);// 出现过不能计入总数 if (loc != -1 && loc != cnt) { family[loc].parent = TempParent; --cnt; } } else if (*(family[cnt].name) == '?') { int loc = search(family[cnt].name, cnt);// ?元素,不计入集合 FindParent[count++] = loc; cnt--; } cnt++; } // while end for (int i = 0; i < count; i++) { int loc = search(family[FindParent[i]].name, cnt);// 找到元素再集合中的位置 int ancestor = find(loc); char *p = family[FindParent[i]].name; char *q = family[ancestor].name;// 找父亲 p++, q++;// 排除前缀+# cout << p << ' ' << q << endl; } return 0; }
END 感谢rueader's阅读,洛谷题目链接:P2814 家谱 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)