笔试—科大讯飞嵌入式软件开发笔试
题型:3道编程题
题目1:
图像的卷积是图像处理的最常用的方法,当前神经网络中的卷积神经网络当中也用到了卷积的操作来提取特征。卷积一般包含以下几个概念:.
1.输入:一个m*n大小的矩阵,是一个二维数组,是图像的数据信息:例如
2 |
3 |
7 |
4 |
6 |
2 |
9 |
6 |
6 |
9 |
8 |
7 |
4 |
3 |
3 |
4 |
8 |
3 |
8 |
9 |
7 |
7 |
8 |
3 |
6 |
6 |
3 |
4 |
4 |
2 |
1 |
8 |
3 |
4 |
6 |
3 |
2 |
4 |
1 |
9 |
8 |
3 |
0 |
1 |
3 |
9 |
2 |
1 |
4 |
记作二维数组I.
2.卷积核:一个k*l大小的矩阵,是一个二维数组,k,I为奇数,保证卷积核有一个中心,例如:
3 |
4 |
4 |
1 |
0 |
2 |
-1 |
0 |
3 |
记作二维数组K,该卷积核的中心就是K[1][1].
(如果K的大小为3*5,则中心为K[1][2])
3.卷积操作:将卷积核的中心对准输入的某个元素,两个矩阵会有重合区域,将两个矩阵的重合区域中的对应重合元素相乘后求和,得到的结果就是输出中对应元素的数据。将卷积核分别从左往右、从上往下进行滑动,重复对重合中的元素进行相乘后求和,就能够完成对整个图像的卷积操作了。例如:
上面的卷积核K的中心对准输入I[0][0],重合部分就有4个元素,卷积结果就是K[1][1]*I[0][0] +K[1][2] * I[0][1] + K[2][1] *1[1][0] + K[2][2]*I[1][1]。
上面的卷积核K的中心对准输入I[2][3],重合部分就有9个元素,卷积结果就是K[0][0]*I[1][2] + K[0][1]*1[1][3] + K[0][2]*I[1][4] + K[1][0]*1[2][2] + K[1][1]*I[2][3]+ K[1][2]*1[2][4] + K[2][0]*1[3][2] + K[2][1]*][3][3] + K[2][2]*I[2][4]
4.输出:将卷积核滑动过程中的卷积结果按照顺序放入一个二维数组中,即图像卷积的输出。
5.滑动步长:卷积核滑动的距离,即卷积核每次滑动经过的元素个数,如果为2即每次滑动跳过一个元素,今天我们仅考虑步长为1的情况,即卷积核会经过每个输入的元素,这样输出数组的大小是跟输入数组的大小是一样的。现在让我们来编程完成一些具体操作吧,并且这次操作有一些特殊的要求,当输出中的元素小于0时要变更为0,当输出中的元素大于255时要变更为255。
输入描述:
第一行输入4个数字M、N、K、L。M、N表示输入数组的大小,K、L表示卷积核的大小。M,N,K,L皆不大于256
之后M行表示输入每行的数据,每行有N个数字。
再之后K行表示卷积核的每行的数据,每行有L个数字。如:
5 6 3 3
1 1 1 1 1 1
1 2 2 2 2 1
2 3 3 1 2 2
1 2 2 3 4 5
5 6 6 6 3 4
1 10 1
1 20 1
1 8 1
输出描述
输出M行数据,每行N个数字,表示卷积后的数据结果如:
31 41 42 42 41 31
52 84 84 69 74 51
65 107 109 79 106 98
91 137 139 138 145 161
110 154 157 165 118 137
示例1
7 7 3 3
2 3 7 4 6 2 9
6 6 9 8 7 4 3
3 4 8 3 8 9 7
7 8 3 6 6 3 4
4 2 1 8 3 4 6
3 2 4 1 9 8 3
0 1 3 9 2 1 4
4 8 4
8 16 8
-4 8 -4
输出
80 108 184 168 152 144 168
180 255 255 255 255 232 180
176 255 255 255 255 255 244
240 255 220 255 255 255 212
184 164 196 200 255 216 164
100 120 120 252 255 255 204
40 84 172 244 220 176 128
#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::min 和 std::max
// 辅助函数,用于打印矩阵
void printMatrix(const std::vector<std::vector<int>>& matrix) {
for (size_t r = 0; r < matrix.size(); ++r) {
for (size_t c = 0; c < matrix[r].size(); ++c) {
std::cout << matrix[r][c] << (c == matrix[r].size() - 1 ? "" : " ");
}
std::cout << std::endl;
}
}
int main() {
// 关闭同步以加速cin/cout
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int M, N, K_rows, L_cols;
// 1. 读取维度
std::cin >> M >> N >> K_rows >> L_cols;
// 创建并读取输入矩阵
std::vector<std::vector<int>> inputMatrix(M, std::vector<int>(N));
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
std::cin >> inputMatrix[i][j];
}
}
// 创建并读取卷积核矩阵
std::vector<std::vector<int>> kernelMatrix(K_rows, std::vector<int>(L_cols));
for (int i = 0; i < K_rows; ++i) {
for (int j = 0; j < L_cols; ++j) {
std::cin >> kernelMatrix[i][j];
}
}
// 创建输出矩阵
std::vector<std::vector<int>> outputMatrix(M, std::vector<int>(N));
// 2. 确定卷积核中心
int centerX = L_cols / 2;
int centerY = K_rows / 2;
// 3. 执行卷积操作
// 遍历输入矩阵的每个像素作为卷积中心
for (int r = 0; r < M; ++r) {
for (int c = 0; c < N; ++c) {
int sum = 0;
// 遍历卷积核的每个元素
for (int kr = 0; kr < K_rows; ++kr) {
for (int kc = 0; kc < L_cols; ++kc) {
// 计算对应的输入矩阵坐标
int input_r = r + (kr - centerY);
int input_c = c + (kc - centerX);
// 边界检查
if (input_r >= 0 && input_r < M && input_c >= 0 && input_c < N) {
sum += inputMatrix[input_r][input_c] * kernelMatrix[kr][kc];
}
}
}
// 4. 处理输出值 (钳位操作)
sum = std::max(0, sum);
sum = std::min(255, sum);
outputMatrix[r][c] = sum;
}
}
// 5. 打印结果
printMatrix(outputMatrix);
return 0;
}
解题思路
- 读取输入:首先,程序需要读取输入矩阵 I 的维度 M, N 和卷积核 K 的维度 K_rows, L_cols。然后,使用嵌套循环读取 M x N 的输入矩阵和 K_rows x L_cols 的卷积核矩阵,并将它们存储在二维向量 std::vector<std::vector<int>> 中。
- 确定卷积核中心:由于题目保证卷积核的维度 K_rows 和 L_cols 都是奇数,其中心点的索引可以很方便地通过整除计算得出:centerY = K_rows / 2 和 centerX = L_cols / 2。
- 执行卷积:创建一个与输入矩阵大小相同的 M x N 的输出矩阵 output,并初始化所有元素为 0。使用两层嵌套循环遍历输入矩阵 I 的每一个像素 I[r][c](其中 r 是行索引,c 是列索引)。I[r][c] 就是当前卷积操作的中心点。对于每一个中心点,再使用两层嵌套循环遍历卷积核 K 的每一个元素 K[kr][kc](其中 kr 是卷积核的行索引,kc 是列索引)。计算当前卷积核元素 K[kr][kc] 对应到输入矩阵 I 上的坐标。计算公式为:input_r = r + (kr - centerY)input_c = c + (kc - centerX)边界检查:在访问输入矩阵的 I[input_r][input_c] 之前,必须检查这个坐标是否越界(即 input_r 是否在 [0, M-1] 范围内,input_c 是否在 [0, N-1] 范围内)。如果坐标有效(在边界内),则将 I[input_r][input_c] * K[kr][kc] 的乘积累加到一个临时变量 sum 中。当遍历完整个卷积核后,sum 就是输出矩阵在 [r][c] 位置的卷积结果。
- 处理输出值:将计算得到的 sum 进行“钳位(Clamp)”操作:如果 sum < 0,则将其设置为 0。如果 sum > 255,则将其设置为 255。将处理后的值存入 output[r][c]。
- 打印结果:最后,遍历输出矩阵 output,按照指定的格式打印所有元素。
题目2:
我们发现一种神奇的粒子,这种粒子有很多细分种类并且很难制造与测量,经过不懈努力,我们制作了一个可以发射这种粒子的粒子枪,和一个可以检测发射出来粒子的检测器。由于技术原因,粒子枪很难发射单一的细分种类的粒子,一次发射可能包含多种细分粒子种类。检测器可以接收粒子枪发射出来的粒子,并且能够检测出来接收到的每种细分种类粒子的个数与接收到的总能量,这些粒子的能量是线性叠加的。现在我们想知道每种细分种类粒了的单个粒子能量,为了方便测验,我们为每种细分种类粒子进行了命名,其中一种细分种类粒子的命名为iflytek,下面就让我们根据实验数据求出单个iflytek粒子的能量吧。
输入描述:
第一行输入为数字N,表示进行了N次发射与检测的实验。
之后N行输入为每次实验的具体数据,每一行的格式如下:
细分粒子1名称 细分粒子1个数 细分粒子2名称 细分粒子2个数...
总能量值(中间用空格隔开>,例如:
iflytek 3 solid 4 liquid 5 50
表示本次实验接收到iflytek粒子个数为3,solid粒子个数为4,liquid粒子个数为5,总能量值为50
输出描述
输出一个数字,表示单个iflytek粒子的能量,如果给定的实验结果无法求出单个iflytek粒子的能量,输出-1
输入样例
3
iflytek 3 solid 2 liquid 1 12
iflytek 5 solid 3 liquid 2 20
iflytek 1 solid 5 liquid 7 26
输出
2
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏主要是介绍嵌入式软件开发岗位的相关知识和学习攻略,为大家提供一份笔试与面试手册。包括有嵌入式软件开发岗位介绍与学习攻略;校园招聘和offer疑惑问题的介绍;在笔试方面,如何刷题为笔试作准备,提供往年笔试真题;在面试方面,提供相关知识的复习重点,提供面试真题。包括有:华为、蔚来、文远、大疆、三一、深信服、亚马逊、Intel、百度、科大讯飞、OPPO、京东、中兴、比特大陆|算能、美团等等
360集团公司氛围 350人发布