关注我们,每天更新大厂最新笔试题解析
前言
文末给大家推荐一下我们的活动,针对校招笔面试全覆盖的全程真一对一的提高,参加活动前会给你安排一个全面的摸底,摸底后会针对你的情况进行分析和对于参加活动的介绍,然后你再决定是否参加!
在线做题链接:https://niumacode.com/
这两道题分别考察了机器学习中的两类基础能力:监督学习与无监督学习。第一题以路由器资源预测为背景,要求使用批量梯度下降训练线性回归模型,并结合特征归一化与参数还原完成结果输出,重点在于理解损失函数、梯度更新和数值处理流程。第二题以快递配送为场景,要求先通过 K-Means 聚类得到社区中心,再按照指定规则规划配送路径并计算总耗时,核心在于聚类迭代、几何距离计算以及过程模拟。
题目一:路由器资源用量预测 (150分)
在线做题链接:https://niumacode.com/
题目描述:路由器的某资源利用率与多个运行特征强相关:协议连接数(单位:个)、转发数据包速率(单位:Mpps)、内存占用率(单位:%)。 为了精准预测不同负载下的路由器资源利用率,保障网络稳定运行,请实现批量梯度下降法(BGD)来训练资源预测线性回归模型的参数。
资源预测模型:( 为偏置项, 分别为特征, 为特征权重)
损失函数:均方误差(MSE),( 为样本数)
梯度更新规则:(偏置项 对应 , 为学习率)
迭代规则:初始权重(含偏置)全为 0,迭代固定 次后停止,无需判断收敛。
为了提高收敛速度,采用特征归一化进行训练,并在训练完成后进行权重还原:
- 特征归一化:对每个特征维度 ():其中 为该特征在所有样本中的最小值, 为该特征在所有样本中的最大值。 若 (即特征无波动),则归一化后的值为 0。
- 特征权重还原:(), 为迭代后的权重。若 ,则 取 0。
输入描述:
- 后续 行:每行 4 个整数,依次为 (协议连接数,范围 )、(转发数据包速率,范围 )、(内存占用率,范围 )、(资源用量,范围 )
输出描述:一行,4 个浮点数,依次为还原后的 ,结果保留 2 位小数,银行家舍入,以一个空格分隔,前后无冗余空格。
样例 1输入:
3
100
0.10
100 200 150 6000
200 800 600 7500
300 70 60 6500
输出:
4394.59 6.82 1.20 1.55
样例 2输入:
2
50
0.05
0 0 0 0
1000 10000 100 100000
输出:
11419.33 28.26 2.83 282.62
import sys
defsolve():
m = int(sys.stdin.readline().strip())
N = int(sys.stdin.readline().strip())
alpha = float(sys.stdin.readline().strip())
X = []
Y = []
# 循环读取 m 行样本数据
for _ in range(m):
parts = sys.stdin.readline().strip().split()
if parts: # 确保非空行
X.append([float(parts[0]), float(parts[1]), float(parts[2])])
Y.append(float(parts[3]))
# 2. 特征归一化
X_min = [min(X[i][j] for i in range(m)) for j in range(3)]
X_max = [max(X[i][j] for i in range(m)) for j in range(3)]
X_norm = [[0.0] * 3for _ in range(m)]
for i in range(m):
for j in range(3):
if X_max[j] == X_min[j]:
X_norm[i][j] = 0.0
else:
X_norm[i][j] = (X[i][j] - X_min[j]) / (X_max[j] - X_min[j])
# 3. 批量梯度下降迭代
w = [0.0, 0.0, 0.0, 0.0] # w0, w1, w2, w3
for _ in range(N):
gradients = [0.0, 0.0, 0.0, 0.0]
for i in range(m):
y_hat = w[0] + w[1] * X_norm[i][0] + w[2] * X_norm[i][1] + w[3] * X_norm[i][2]
diff = y_hat - Y[i]
gradients[0] += diff * 1.0
gradients[1] += diff * X_norm[i][0]
gradients[2] += diff * X_norm[i][1]
gradients[3] += diff * X_norm[i][2]
for j in range(4):
w[j] -= alpha * (gradients[j] / m)
# 4. 特征权重及偏置项还原
w_prime = [0.0, 0.0, 0.0, 0.0]
for j in range(1, 4):
if X_max[j - 1] == X_min[j - 1]:
w_prime[j] = 0.0
else:
w_prime[j] = w[j] / (X_max[j - 1] - X_min[j - 1])
w_prime[0] = w[0] - (w_prime[1] * X_min[0] + w_prime[2] * X_min[1] + w_prime[3] * X_min[2])
# 5. 格式化输出 (Python的round默认是银行家舍入)
result = [f"{round(w_prime[i], 2):.2f}"for i in range(4)]
print(" ".join(result))
if __name__ == "__main__":
solve()
题目二:快递员极速配送挑战 (300分)
在线做题链接:https://niumacode.com/
题目描述:某快递员负责一个片区的快递配送业务。假设他手头有 个快递包裹需要派送,每个包裹对应一个具体的收货坐标(单位:公里)。 为了提高效率,公司要求快递员先利用聚类算法将这 个包裹自动划分为 个簇(代表 个社区),快递员只需要将快递送到社区中心(类的中心点)即可。
快递员从起始位置出发,按照每个社区中心与起点之间的距离由近到远排序,依次送完所有社区的快递,最后返回起始位置。 已知快递员的平均行驶速度为 speed km/h。快递员初始坐标为 。 请编写程序,计算完成所有配送并返回起点所需的总时间(单位:秒,向下取整)。
K-Means 聚类计算步骤:
- 将所有点按到起点的距离从小到大排序,如果距离相同的点,按照输入坐标点的先后顺序从小到大排序。
- 重新计算每个聚类的中心点(即分配到该簇的坐标点的均值),移动聚类中心。
- 如果所有聚类中心的移动距离之和小于
1e-4,则停止迭代。 - 如果达到了预设的最大迭代轮次(50次),也停止迭代。
解题约束及提示:
- 种子点的选择:对距离信息进行升序排序,选择前 个点进行初始化。
- k-Means 终止条件:设定常数
const int max_iters = 50; const double tol = 1e-4;
输入描述:
- 第一行输入 3 个由空格分隔的整数,分别为 (社区个数)、(快递包裹总数)、(快递员平均行驶速度,单位 km/h)。
- 接下来的 行分别表示每个包裹的 和 坐标(单位:公里),用空格分割。
输出描述:输出快递员送完所有快递所需的时间,保留整数,向下取整,单位 s。
样例 1输入:
3 10 30
1.2 1.5
1.8 1.2
5.0 5.2
5.5 4.8
4.9 5.5
-2.0 3.0
-2.5 3.5
-1.8 2.8
1.5 1.8
5.2 5.0
输出:
2502
说明: 聚类后的 3 个聚类中心按照距离起点的位置远近排序分别为:(1.5, 1.5),(-2.1, 3.1),(5.15, 5.125)。算出快递员配送总时间约为 2502 秒。
样例 2输入:
5 3 10
1.00 1.00
2.00 2.00
3.00 3.00
输出:
3054
说明: 由于 5 > 3,3 个包裹本身分别构成了 3 个聚类中心。按照距离起点位置的排序配送的路径为:(0, 0) --> (1, 1) --> (2, 2) --> (3, 3) --> (0, 0)。总距离为 km,配送速度为 10 km/h,总耗时向下取整后为 3054 秒。
import sys
import math
def get_dist(p1, p2):
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
def solve():
parts = sys.stdin.readline().strip().split()
K = int(parts[0])
N = int(parts[1])
speed = float(parts[2])
points = []
# 循环读取 N 行包裹坐标
for i in range(N):
parts = sys.stdin.readline().strip().split()
if parts: # 确保非空行
points.append({
'id': i, # 记录原始索引,用于距离相同时的稳定排序
'x': float(parts[0]),
'y': float(parts[1])
})
origin = (0.0, 0.0)
# 2. 种子点初始化
# 按距离原点的距离从小到大排序,距离相同按输入顺序
points.sort(key=lambda p: (get_dist((p['x'], p['y']), origin), p['id']))
actual_K = min(K, N)
centers = [(points[i]['x'], points[i]['y']) for i in range(actual_K)]
# 3. K-Means 迭代
max_iters = 50
tol = 1e-4
for _ in range(max_iters):
clusters = [[] for _ in range(actual_K)]
# 将点分配到最近的聚类中心
for p in points:
p_coords = (p['x'], p['y'])
min_d = float('inf')
best_c = -1
for i, c in enumerate(centers):
d = get_dist(p_coords, c)
if d < min_d:
min_d = d
best_c = i
clusters[best_c].append(p_coords)
# 计算新聚类中心并累加移动距离
new_centers = []
move_sum = 0.0
for i in range(actual_K):
if not clusters[i]:
# 若无点分配到该簇,保持原中心点不变
new_centers.append(centers[i])
else:
avg_x = sum(pt[0] for pt in clusters[i]) / len(clusters[i])
avg_y = sum(pt[1] for pt in clusters[i]) / len(clusters[i])
new_centers.append((avg_x, avg_y))
move_sum += get_dist(centers[i], (avg_x, avg_y))
centers = new_centers
# 判断收敛
if move_sum < tol:
break
# 4. 计算路径及时间
# 社区中心按到原点的距离由近到远排序
centers.sort(key=lambda c: get_dist(c, origin))
total_dist = 0.0
curr = origin
for c in centers:
total_dist += get_dist(curr, c)
curr = c
total_dist += get_dist(curr, origin) # 最后返回起始位置
# 距离单位是公里,速度是 km/h,换算成秒向下取整
time_s = math.floor((total_dist / speed) * 3600)
print(time_s)
if __name__ == "__main__":
solve()