9.1号的机试终于来了,怀着被暴击的心情,提前15分钟打开了浏览器,等待着“开始答题"。 终于到19:00了,点击”开始答题“,粗略的看了三道题,好家伙,除了最后一道题,其余题目都超长。这不是编程,这是阅读理解啊。热乎的解题思路走起。——2021.9.1华为秋招机试
由于很多题忘记标题了,所以自己取了一个
三道题
第一题 序列转发
题目大致描述
就是存在一个k个的序列,其中每个节点都是类似于一个转发器,有m个容量的转发量和n个容量的缓存区,从开始节点输入某随机的数据量作为第一个节点的接收量,在不超出所有节点转发能力和缓存能力的情况下,经过两轮转发,其中第二轮无输入,由开始节点的缓存区驱动,既第二轮转发由开始节点的缓存区驱动,求整个节点转发量最少的情况。
坑点:由于故障,某些节点只能直接传送(不计入总的转发量中,相当于直接连一根线),但不存在连续2个节点故障,所以需要我们对某些节点透明化,且确保故障节点不连续。
解题大致思路
看了整个题目,首先想到的就是对节点进行分析,对节点抽象,能得到一个类如下:
class jie{
public:
jie(int a,int b):m(a),n(b){}
int shou=0;//接受量
int m,n;
int zhuan=0,cun=0;//转发量和缓存量
void operator+(jie& next){//二者工作
next.shou=this->zhuan+next.cun;//接收前面一个节点的转发,注意这里包括了当前节点的缓存量,第一轮中默认为0,确保程序正确
if(next.shou<next.m){
next.zhuan=shou;
next.cun=0;
}else{
next.zhuan=next.m;
next.shou-=next.m;
if(next.shou<next.n){
next.cun=next.shou;
}else{
next.cun=next.n;
}
}
}
};
由于是前一个节点的转发会影响后面的接受,所以我重载了+号运算符,表示两个节点之间的工作,
对第一轮转发描述
jie start(0, 0);
start.zhuan = shuru; //构造第一轮转发输入节点
start + vt.at(0); //跟首个节点进行工作
//第一轮
for (int i = 0; i < vt.size(); i++){
res += vt.at(i).zhuan; //依次对转发量进行统计
}
第二轮转发描述
jie end(0,0);
end+vt.at(0);
for(int i=0;i<vt.size();i++){
res+=vt.at(i).zhuan;
}
基本上以上代码能够应付n=1,n=2的情况了,但是对于n>=3的情况,则需要对序列进行筛选,我们观察n=1,n=2的转发情况,如果一个节点的m+n远远小于前面一个节点,那么整个序列的转发量最终都是由后面一个节点控制,既谁最小,谁就是瓶颈。根据这个思路,先对序列排序,找出前面最小的几个,然后两个最小的之间不能超过2个故障节点的方法,对2个节点进行标记,若某一个节点不满足约束条件,则对该结点进行交换,然后重新判断,直到遍历完所有的结点,生成选取标记,根据标记结果统计转发量。
代码未完待续
第二题 类与继承
题目大致描述
开头扯了很多关于知识图谱的事情,但这些都不重要,重要的是后面一部分描述,说的是现实世界中,存在很多概念,比如子概念、实例概念(这不就是类的继承、实现?),然后说类似于知识图谱,我们用三元组来定义关系,比如 student subClassOf people 来代表一种子概念,表明student是people的子概念,又比如 apple instanceOf fruit 来代表一种实例概念,表明apple是fruit的实例概念。问,给出n个关系的描述,求 某个类 的所有实例名称(包括子类的实例)。
坑点:1.题目要求字典序输出 2.关系的定义对大小写敏感,也就是说,存在关系错误定义的情况,题目的意思是忽略这种情况
降低难度点:1.关系不存在回路定义,也就是类不会成为类的子类 2.确保关系定义只有三元组形式
解题大致思路
整个解题思路都是围绕继承和实现展开,中心点在类的构建上,根据题意,我们知道一个类,包括了类名,实例对象集合,子类对象集合,所以可以构建一个类叫obj代表类
// 首先定义一个类
class obj{
public:
obj(string a,int d):name(a),id(d){}
string name;//类名字
int id=0; //类id
vector<int> shili;//直接实例
vector<int> zilei;//子类
};
然后创建一个容器,保存所有的类
// 存储所有概念
vector<obj> vt;
关系的定义,和结果的保存都存在对类对象查找,所以必须构建一个容器,用来保存类对象的索引,我想到了map容器
//存储所有的索引
map<string,int> mp;
在这里,mp和vt一一对应,确保索引的准确性。这些容器构建成功,接下来就是对三元组关系定义,进行语义分析了。拆分字符串,将类对象1 关系定义类型 类对象2拆分出来,然后处理,就能得到每个类相互关联的结构
//关系词都处理完毕
if(type==0){//不满足任何要求,不处理
;
}else{//处理三元组关系
if(type==ZILEI){//处理子类关系
vt.at(idx3).zilei.push_back(idx1);
}
if(type==SHILI){//处理子类关系
vt.at(idx3).shili.push_back(idx1);
}
}
最后,根据题目要求,找出对应类,保存实例结果。由于需要按字典序输出,所以首先想到用set容器保存结果,并且还存在子类还有子类的递归情况,所以需要构造递归函数,遍历所有结果(这里可以不用栈和队列,因为该递归为不回溯的递归,所以基本上不会爆内存)
void tianjia(set<string>& res,vector<obj>& vt,int idx){
obj rs=vt.at(idx);
//处理当前类的实例对象
vector<int> shi=rs.shili;
for(vector<int>::iterator it=shi.begin();it!=shi.end();it++){
res.insert(vt.at(*it).name);
}
// 再然后取出子类对象
vector<int> zi=rs.zilei;
for(vector<int>::iterator it=zi.begin();it!=zi.end();it++){
// 对于每个子类对象进行递归调用
tianjia(res,vt,*it);
}
}
最后,非常坑的一点就是,华为对输入输出很严格,最后输出结果少了一个空格,折腾我半天。
第三题 湖泊联通
题目大致描述
用一个m*n的矩阵描述一个地面情况,其中0代表湖泊,1代表陆地,2代表岩石,湖泊数量不固定,分布也不确定,如果打通一个陆地代价为1,打通一个岩石代价为2,问:最少需要多少代价能使得整个湖泊连通
坑点:这道题既不是考验dfs等遍历情况也不是考验动态规划,等走一步看一步
降低难度点:对角不算连通,也就是说湖泊联通的条件只有上下左右
解题大致思路
第一眼看到这个题,非常头疼,因为这既不像”迷宫问题",那种dfs遍历+剪枝就能解决,因为不存在唯一结果,也不像动态规划,下一步根据记录选择最优,因为最优解不止一个,目前还没有想法。
等待有缘大佬评论区更新。。
最后,经过将近半个月的时间学习,我对C++的熟练度又上升了,趁着热乎劲,还能把CCF也解决掉。