通过率 100% · 提交 1 · 通过 1
使用训练集的列最小值和最大值完成 Min-Max 归一化,再从零参数开始执行固定轮数的批量梯度下降,最后预测查询样本。常量特征归一化为 0,查询值不做区间截断。
这类题属于算法机考高频题型中「华为 AI 岗 / 线性回归」方向的高频题型,通常考察对「华为 AI 岗 / 线性回归」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入 n d m e,第二行输入学习率 eta。接下来 n 行包含 d 个整数特征和一个实数标签,随后 m 行包含 d 个整数特征。
输出 m 行,每行一个保留四位小数的预测值;绝对值小于 0.00005 时输出 0.0000。
示例 1
输入示例
2 1 2 1 0.1 0 1 10 3 0 10
输出示例
0.4000 0.7000
一轮批量更新后 b=0.4,w=0.3。
示例 2
输入示例
2 2 1 0 0.2 0 0 5 10 20 9 5 10
输出示例
0.0000
训练轮数为 0,参数保持为 0。
时间限制 3000 ms · 内存限制 256 MB
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
这些是真正决定能不能 AC、但通用题解里常被略过的点。
线性回归的完整训练管线:Min-Max 归一化 + 固定轮数批量梯度下降 + 查询预测。考的是训练纪律——参数从哪来、梯度长什么样、更新怎么做,每一处都有明确约定。
每列的 min 和 max 从训练集统计,查询样本用同一组参数换算,超出 [0,1] 也不截断——比如查询值大于训练最大值时归一化结果就大于 1,保持原样参与预测。两个约定要盯住:
损失是均方误差 L = (1/n)·Σ(pred−y)²,对参数求导会带出系数 2:
判题的期望输出按这个口径生成,漏掉 2 或多除一个 2,前几轮的数值就分道扬镳了。
一轮里所有梯度基于同一组旧参数计算,算完再一起更新。逐参数即时更新(算完 b 立刻改 b,再用新 b 算 w 的梯度)是最隐蔽的错法——样例小可能侥幸接近,构造用例必然暴露。实现上先把全部梯度存进临时变量,最后统一赋值。
1. 读训练集,统计每列 min/max,归一化训练集与查询集。 2. 参数全部从 0 出发,跑 e 轮:每轮先算全部预测值,再累加梯度,最后同步更新。 3. e 可能为 0:零参数直接预测,全部输出为 0.0000 的路径也要正确。 4. 查询逐个输出,保留四位小数,绝对值小于 0.00005 输出 0.0000(负零钳制)。
时间 O((n+m)·d + e·n·d),空间 O(n·d + d)。
-0.0000 未钳制。样例 1:n=2、d=1、e=1、eta=0.1,训练对 (x=0, y=1) 和 (x=10, y=3)。列范围 0→10,归一化后 x̂ 为 0 和 1。参数从 b=w=0 出发,预测全为 0,误差为 −1 和 −3:
查询 x=0 归一化为 0,预测 0.4;x=10 归一化为 1,预测 0.4+0.3=0.7。输出 0.4000 与 0.7000,与样例一致。注意 grad_b 里那个 2:漏掉它,这一轮得到 b=0.2、w=0.15,第一行就对不上。
被问「手写一个线性回归」时,值得先说清三句话再动笔:损失用 MSE、梯度是 (2/n)·Σ(误差)·x、一轮内同步更新。写完常见的追问是「为什么要先归一化」——答案在梯度里:特征量级差几个数量级时,各参数的梯度大小同样差几个数量级,同一个学习率要么让大梯度方向震荡、要么让小梯度方向蜗牛,先把各列拉到同一尺度,一个学习率才伺候得了所有参数。能把「归一化参数只来自训练集」这条纪律主动讲出来,是这道题从「会写」到「懂了」的分界线。
# Min-Max 用训练集的列 min/max(常量列归 0),查询同参数换算不截断;
# 批量 GD:MSE 梯度带 2/n 系数,一轮内基于旧参数算完全部梯度再同步更新。
import sys
def solve() -> None:
data = sys.stdin.buffer.read().split()
if not data:
return
it = iter(data)
n, d, m, epochs = (int(next(it)) for _ in range(4))
eta = float(next(it))
x, y = [], []
for _ in range(n):
x.append([float(next(it)) for _ in range(d)])
y.append(float(next(it)))
query = [[float(next(it)) for _ in range(d)] for _ in range(m)]
lo = [min(row[j] for row in x) for j in range(d)]
hi = [max(row[j] for row in x) for j in range(d)]
def norm(row):
return [0.0 if hi[j] == lo[j] else (row[j] - lo[j]) / (hi[j] - lo[j]) for j in range(d)]
train = [norm(row) for row in x]
weights = [0.0] * d
bias = 0.0
for _ in range(epochs):
grad_w = [0.0] * d
grad_b = 0.0
for row, target in zip(train, y):
error = bias + sum(weights[j] * row[j] for j in range(d)) - target
grad_b += error
for j in range(d):
grad_w[j] += error * row[j]
scale = 2.0 / n
bias -= eta * scale * grad_b
for j in range(d):
weights[j] -= eta * scale * grad_w[j]
out = []
for row in query:
row = norm(row)
value = bias + sum(weights[j] * row[j] for j in range(d))
if abs(value) < 0.00005:
value = 0.0
out.append(f"{value:.4f}")
print("\n".join(out))
if __name__ == "__main__":
solve()
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有