菜鸡学C语言之寻根溯源
题目描述
Mogg最近翻了翻自己家的族谱,想康康祖先是谁。但是族谱因为年久失修太乱了,他现在只整理出来了一系列父子关系,你能帮他找一找直系亲属中辈分最大的一位吗?(即父亲的父亲的父亲……)
输入
第1行,一个整数n,表示有n个父子关系(0≤n≤1500)
接着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[][];
char son[][]; int main() {
int n;
char name[];
scanf("%d", &n);
for(int i = ; i <= n; i++)
scanf("%s%s", father[i], son[i]);
scanf("%s", name); // 记录待查找的名字
int flag = ; // 用来标记是否查到当前人的父亲
int cnt = ; // 记录查找次数
while(flag) {
flag = ;
for(int i = ; i <= n; i++) {
if(!strcmp(son[i], name)) {
strcpy(name, father[i]); // 下次查找此次查找人的父亲
cnt++;
flag = ;
break;
}
}
}
printf("%s %d", name, cnt);
return ;
}
附:这是十分容易写出来的一种方法,适用在考试这种时间紧张的情形中。
解法二:
改进措施:降维处理+使用指针数组
思路:
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[ * N] = {}; // 将所有出现人的名字用一个数组来保存
int num_of_mans = ;
int relations[ * N] = {}; // 记录父子关系
// relations[i] = j 表明i的父亲是j, 其中i、j为在mans数组中的索引
// 当j = -1时, 表示此人没有父亲 char* addMan(const char* name) {
char* newman = ;
if(!name) return newman;
newman = (char*)malloc(strlen(name)+);
strcpy(newman, name);
mans[num_of_mans++] = newman;
return newman;
} void initRelations() {
int i;
for(i = ; i < * N; i++) {
relations[i] = -;
}
} int findMan(char name[]) {
int i;
for(i = ; i < num_of_mans; i++) {
if(strcmp(name, mans[i]) == ) {
return i;
}
}
return -;
} int insertMan(char name[]) {
// 如果待插入的人已存在,则返回其在mans数组中的索引值;
// 否则增加一个新元素并返回其索引值
int id;
id = findMan(name);
if(id >= ) {
return id;
}
addMan(name);
return num_of_mans - ;
} void addFatherSon(int father, int son) {
relations[son] = father;
} int findRoot(int id, int *count) {
int root;
*count = ;
while(id >= ) {
root = id;
id = relations[id];
if(id >= )
(*count)++;
}
return root;
} int main() {
int i;
char father[M], son[M], target[M];
int fid, sid, tid, rid, count = ;
int num; initRelations(); // 初始化所有人没有父亲
scanf("%d", &num);
for(i = ; 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 == -) { // 没有存入此人信息,即没有父亲
printf("%s %d", target, count);
} else {
rid = findRoot(tid, &count);
printf("%s %d", mans[rid], count);
}
return ;
}
菜鸡学C语言之寻根溯源的更多相关文章
- 菜鸡学C语言之真心话大冒险
题目描述 Leslie非常喜欢真心话大冒险的游戏.这一次游戏的规则有些不同.每个人都有自己的真心话,一开始每个人也都只知道自己的真心话.每一轮每个人都告诉指定的一个人他所知道的所有真心话,那么Lesl ...
- 菜鸡学C语言之摸鱼村村长
题目描述 摸鱼村要选村长了! 选村长的规则是村里每个人进行一次投票,票数大于人数一半的成为村长. 然鹅摸鱼村的人都比较懒,你能帮他们写一个程序来找出谁当选村长吗? (每名村民的编号都是一个int范围内 ...
- ACM菜鸡退役帖——ACM究竟给了我什么?
这个ACM退役帖,诸多原因(一言难尽...),终于决定在我大三下学期开始的时候写出来.下面说两个重要的原因. 其一是觉得菜鸡的ACM之旅没人会看的,但是新学期开始了,总结一下,只为了更好的出发吧. 其 ...
- HDU 2064 菜鸡第一次写博客
果然集训就是学长学姐天天传授水铜的动态规划和搜索,今天讲DP由于困意加上面瘫学长"听不懂就是你不行"的呵呵传授,全程梦游.最后面对连入门都算不上的几道动态规划,我的内心一片宁静,甚 ...
- 菜鸡谈OO 第二单元总结
“欢迎来到(玄学)多线程的新世界” Homework1 单部傻瓜电梯调度 Part1 多线程设计策略 第一次学到了线程这个概念,与之前的编程体验大有不同.最大的区别在于从原本的线性发生程序变成了多个行 ...
- 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记
一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...
- Html菜鸡大杂烩
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- 小C的故事(快速学C语言,,,极速版!)
前几天这篇博客写了太多废话! 删啦~~. 本篇博客只是为chd A协的全嫩小鲜肉入门C语言的预科, 如果你在此处学习C语言, 不幸走火入魔, 小弱概不负责. //请直接随便找个C语言编译器,抄一下下面 ...
- 边看MHA源码边学Perl语言之一开篇
边看MHA源码边学Perl语言之一开篇 自我简介 先简单介绍一下自己,到目前为此我已经做了7年左右的JAVA和3年左右php开发与管理,做java时主要开发物流行业的相关软件,对台湾快递,国际快递,国 ...
随机推荐
- JAVA常用加密解密算法Encryption and decryption
加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容.大体上分为双向加密和单向加密,而双向加密又分为对称加密和非对称加密(有些 ...
- sql server导出数据,详细操作!(自用)
右键数据库——>任务——>导出数据 填写数据源连接信息 填写 要导入的数据库 连接信息 导出表时,全选,[编辑映射],勾选启用标识插入,这样才能让自增的字段 行正常插入. 然后导出即可. ...
- 区块链名词解析:ICO、IFO、IEO和IMO,分别是什么呢?
区块链名词解析:ICO.IFO.IEO和IMO,分别是什么呢?本部分给出了标准答案,但其相当枯燥乏味,建议快进. ICO(Initial Coin Offering),首次代币发行,指区块链项目首次向 ...
- Qt QGraphicsItem要点 积累
1.在创建QGraphicsItem子类的时候,想要实现自己绘图,一般是重新实现boundingRect()和paint()函数,如果不重新实现shape(),基类的实现将会退而使用 bounding ...
- CH 5102Mobile Service题解
题目: 用动态规划很容易将完成任务量作为dp的阶段,通过指派服务员,从当前i-1个任务转移到i个任务: 我们可以用一个四维数组f[i][x][y][z]来表示在完成当前任务i时,三个机器人分别在x,y ...
- jenkins 启动被杀死
1.重设环境变量build_id 在execute shell输入框中加入BUILD_ID=DONTKILLME,即可防止jenkins杀死启动的tomcat进程 2.在启动jenkins 的时候禁止 ...
- Java基础学习-计算机存储单元和数据类型概述
变量是内存中的小容器,用来存储数据.那么计算机内存是怎么存储数据的呢?无论是内存还是硬盘,计算机存储设备的最小信息单元叫“位(bit)”,我们又称之为“比特位”,通常用小写字母b表示.而计算机最小的存 ...
- Easy to Remember Color Guide for Non-Designers
Notes: I'm not a designer. This is what i've self-learnt over the years because i couldn't afford go ...
- LintCode 1.A+B的问题
LintCode 1.A+B的问题 描述 给出两个整数 a 和 b , 求他们的和. 答案 public class Solution { /** * @param a: An integer * @ ...
- macOS在使用音视频通话时会降低其他音频声音的解决方法
在使用QQ进行通话时,背景无法播放音乐(声音过小),并且在QQ for mac中也没有进行调整的设置选项. Solution: printf "p *(char*)(void(*)())Au ...