zoukankan      html  css  js  c++  java
  • 菜鸡学C语言之寻根溯源

    题目描述

    Mogg最近翻了翻自己家的族谱,想康康祖先是谁。但是族谱因为年久失修太乱了,他现在只整理出来了一系列父子关系,你能帮他找一找直系亲属中辈分最大的一位吗?(即父亲的父亲的父亲……)

    输入

    第1行,一个整数n,表示有n个父子关系(0n1500)

    接着n行,每行两个名字中间用空格分隔,前一个是后一个的父亲

    第n+2行,一个名字

    (不存在重名的情况,名字的长度都小于20)

    输出

    对于每组数据,输出最后一行名字的直系祖辈中,辈分最大的人的姓名,以及向上查询的次数。

    输入样例

    7
    Ben Danny
    Danny Winnie
    Danny Wendy
    Ben Peter
    Peter Eric
    Peter Susan
    Peter Ted
    Ted

    输出样例

    Ben 2

    题目链接https://buaacoding.cn/problem/2058/index

    题目分析:本题按照常规做法,不考虑时间复杂度算是道比较简单的题。由于种种原因,在航C上机前我没有来得及做这道题,所以他们上机时候我也在思考这道题,老师对这道题给出十分经典而且优秀的算法,而且现场码完代码,令人肃然起敬~

    易错点:n=0的情况,即要查找的人没有父亲,父子关系中没有他,说明他就是最高辈。

    解法一:

    表面上看去,是个二维数组的题,将所有父子姓名都保存下来,每次都循环遍历查找即可。

    题目给出的数据范围并不大,而且只需要查找一次,我们可以把这个关系表存下来,然后首先查找当前这个人的父亲,将这个过程“递归”下去,直到查找不到当前这个人的父亲,我们就找到了辈分最大的人

    不过这种做法还是存在一定的弊端:

    1. 字符串存在重复存储,空间效率较低

    2. 查询父亲的过程需要用到strcpy和strcmp函数,时间效率较低

    3. 如果需要用到大量的查询操作,效率问题更为明显。

    #include <stdio.h>
    #include <string.h>
    
    char father[1600][30];
    char son[1600][30];
    
    int main() {
        int n;
        char name[30];
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%s%s", father[i], son[i]);
        scanf("%s", name);    // 记录待查找的名字
        int flag = 1;        // 用来标记是否查到当前人的父亲 
        int cnt = 0;        // 记录查找次数 
        while(flag) {
            flag = 0;
            for(int i = 1; i <= n; i++) {
                if(!strcmp(son[i], name)) {
                    strcpy(name, father[i]);    // 下次查找此次查找人的父亲 
                    cnt++;
                    flag = 1;
                    break;
                }
            }
        }
        printf("%s %d", name, cnt);
        return 0;
    }

    附:这是十分容易写出来的一种方法,适用在考试这种时间紧张的情形中。

    解法二:

    改进措施:降维处理+使用指针数组

    思路:

    1. 人名和关系分别用两个一维数组存,人名是指针数组,关系是int数组

    2. 每次输入两个名字时,动态插入到指针数组中,并用malloc开辟空间,这样可以节省大量内存;

    3. 关系存在int数组中,人名数组不处理关系问题,简化操作;

    4. 查询的时候使用int数组,查询效率要比检查字符串高很多很多

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define N 1500
    #define M 21
    
    char* mans[2 * N] = {0};    // 将所有出现人的名字用一个数组来保存 
    int num_of_mans = 0;
    int relations[2 * N] = {0};    // 记录父子关系
                                // relations[i] = j 表明i的父亲是j, 其中i、j为在mans数组中的索引
                                // 当j = -1时, 表示此人没有父亲 
    
    char* addMan(const char* name) {
        char* newman = 0;
        if(!name) return newman;
        newman = (char*)malloc(strlen(name)+1);
        strcpy(newman, name);
        mans[num_of_mans++] = newman;
        return newman;
    }
    
    void initRelations() {
        int i;
        for(i = 0; i < 2 * N; i++) {
            relations[i] = -1;
        }
    }
    
    int findMan(char name[]) {
        int i;
        for(i = 0; i < num_of_mans; i++) {
            if(strcmp(name, mans[i]) == 0) {
                return i;
            }
        }
        return -1;
    }
    
    int insertMan(char name[]) {
        // 如果待插入的人已存在,则返回其在mans数组中的索引值;
        // 否则增加一个新元素并返回其索引值 
        int id;
        id = findMan(name);
        if(id >= 0) {
            return id;
        }
        addMan(name);
        return num_of_mans - 1;
    }
    
    void addFatherSon(int father, int son) {
        relations[son] = father;
    }
    
    int findRoot(int id, int *count) {
        int root;
        *count = 0;
        while(id >= 0) {
            root = id;
            id = relations[id];
            if(id >= 0)
                (*count)++;
        }
        return root;
    }
    
    int main() {
        int i;
        char father[M], son[M], target[M];
        int fid, sid, tid, rid, count = 0;
        int num;
    
        initRelations();    // 初始化所有人没有父亲 
        scanf("%d", &num);
        for(i = 0; i < num; i++) {
            scanf("%s%s", father, son);
            fid = insertMan(father);
            sid = insertMan(son);
            addFatherSon(fid, sid);    // 建立父子关系 
        }
        scanf("%s", target);
        tid = findMan(target);    // 找到当前待查找人的索引 
        if(tid == -1) {            // 没有存入此人信息,即没有父亲 
            printf("%s %d", target, count);
        } else {
            rid = findRoot(tid, &count);
            printf("%s %d", mans[rid], count);
        }
        return 0; 
    }
  • 相关阅读:
    Django的templates(模板)
    Django的urls(路由)
    Markdown中实现折叠代码块
    图片上传2
    Comparator 排序
    Serializable 序列化为文件
    统计连续签到的方法
    Serializable 序列化为字符串 base64
    Serializable 序列化使用限制
    Serializable 剔除某些不想保存的字段 transient
  • 原文地址:https://www.cnblogs.com/flying-rabbit/p/10733599.html
Copyright © 2011-2022 走看看