小韦老师@神犇营-my0414-家谱

小韦老师@神犇营-my0414-家谱

题目:

描述

现代的人对于本家族血统越来越感兴趣,现在给出充足的父子关系,请你编写程序找到某个人的最早的祖先。

输入

输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系由二行组成,用 #name 的形式描写一组父子关系中的父亲的名字,用 +name 的形式描写一组父子关系中的儿子的名字;接下来用 ?name 的形式表示要求该人的最早的祖先;最后用单独的一个 $ 表示文件结束。规定每个人的名字都有且只有 6 个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有 1000 组父子关系,总人数最多可能达到 50000 人,家谱中的记载不超过 30 代。

输出

按照输入的要求顺序,求出每一个要找祖先的人的祖先,每一行的格式:本人的名字+一个空格+祖先的名字。

输入样例1

#George
+Rodney
#Arthur
+Gareth
+Walter
#Gareth
+Edward
?Edward
?Walter
?Rodney
?Arthur
$

输出样例1

Edward Arthur
Walter Arthur
Rodney George
Arthur Arthur

题解:

思路

整体思路:

这道题就是考查并查集,只是儿子和父亲从之前的整数都变成了字符串。

回顾之前我们用 int father[] 来存储并查集,做的是 儿子(整数)->父亲(整数) 的映射,而此处我们需要做 儿子(字符串)->父亲(字符串) 的映射,因此可以用 map 来完成。

其余的做法与一般的并查集一样。

具体步骤:
  1. 定义一个 map,用来做 儿子(字符串)->父亲(字符串) 的映射:
	// 相当于一个下标为字符串类型,值也为字符串类型的数组 
	map<string, string> father;
  1. 定义 4 个字符串:
    string str;  // 暂存输入的字符串 
    string fa;  // 存储父亲 
    string child;  // 存储孩子 
    string query;  // 查询 
  1. 一直输入一个字符串,若输入的字符串为 $,则退出循环结束;否则做以下的操作:
    if (str[0] == '#') {  // 若 str 以 # 开头,则说明输入的是父亲 
    	// 把 str 除了第一个位置以外都赋值给 fa 
    	fa = str.substr(1, str.size() - 1);  
    if (father.count(fa) == 0)  // 若 fa 未出现过 
    	father[fa] = fa;  // 初始化 fa 
    }
    else if (str[0] == '+') {  // 若 str 以 + 开头,则说明输入的是儿子 
    	// 把 str 除了第一个位置以外都赋值给 child 
    	child = str.substr(1, str.size()-1);  
    	father[child] = fa;  // 将该 child 的父亲置为刚刚输入的 fa 
    }
    else if(str[0]=='?') {   // 若 str 以 + 开头,则说明要进行查询 
    	// 把 str 除了第一个位置以外都赋值给 query
    	query = str.substr(1, str.size()-1);  
    	// 输出 query 以及 query 所在集合的根(祖先) 
    	cout << query << " " << findFather(query) << endl;
    }

4.实现查找函数:

	// 查找 x 所在集合的根 
    string findFather(string x) {

		while (x != father[x]) {
			x = father[x];
		}

		return x;
	} 
思考:

1° 这道题的知识点可以分解为:并查集 + map,你能自己总结一下 map 的常用操作吗?顺便也可以总结下其他 STL 容器。

2° 这道题让你对并查集有了哪些新的认识和理解?

完整代码:
#include <bits/stdc++.h>

using namespace std;

// 用来存储 儿子-> 父亲 的映射
// 相当于一个下标为字符串类型,值也为字符串类型的数组 
map<string, string> father; 

// 查找 x 所在集合的根 
string findFather(string x) {
	
    while (x != father[x]) {
    	x = father[x];
	}
    
	return x;
}

int main() {
	
    string str;  // 暂存输入的字符串 
    string fa;  // 存储父亲 
	string child;  // 存储孩子 
	string query;  // 查询 
    while (1) {
    	cin >> str;  // 输入的字符串暂存在 str 中 
		if (str == "$") break;  // 若 str 为 $,则退出循环结束 
        if (str[0] == '#') {  // 若 str 以 # 开头,则说明输入的是父亲 
        	// 把 str 除了第一个位置以外都赋值给 fa 
            fa = str.substr(1, str.size() - 1);  
            if (father.count(fa) == 0)  // 若 fa 未出现过 
                father[fa] = fa;  // 初始化 fa 
        }
        else if (str[0] == '+') {  // 若 str 以 + 开头,则说明输入的是儿子 
        	// 把 str 除了第一个位置以外都赋值给 child 
            child = str.substr(1, str.size()-1);  
            father[child] = fa;  // 将该 child 的父亲置为刚刚输入的 fa 
        }
        else if(str[0]=='?') {   // 若 str 以 + 开头,则说明要进行查询 
        	// 把 str 除了第一个位置以外都赋值给 query
            query = str.substr(1, str.size()-1);  
            // 输出 query 以及 query 所在集合的根(祖先) 
            cout << query << " " << findFather(query) << endl;
        }
    }
    return 0;
}

我是小韦老师,企者不立,跨者不行,每天进步一点点。

欢迎大家多多交流,如果发现有错误,请多指正。有疑问的同学也可以留言评论或者发邮件。邮箱:weichangying_wcy@163.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值