P2814 家谱

时间:2021-07-12
本文章向大家介绍P2814 家谱,主要包括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 也就是说,+对应的节点内要存储#的位置,此处分为两种情况:

  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)

原文地址:https://www.cnblogs.com/kirk-notes/p/15001382.html