通过率 0% · 提交 0 · 通过 0
单标签多分类任务,类别编号 0 到 k-1。给定 n 个样本的真实标签与预测标签,对每个类别 c:TP 是真实与预测都为 c 的样本数,FP 是预测为 c 但真实不是的样本数,FN 是真实为 c 但预测不是的样本数。precision = TP / (TP + FP),recall = TP / (TP + FN),F1 = 2TP / (2TP + FP + FN);任何一个分母为 0 时,对应指标按 0 处理。宏平均 F1 是全部 k 个类别 F1 的算术平均(数据中没出现过的类别同样计入);微平均 F1 = 2·ΣTP / (2·ΣTP + ΣFP + ΣFN),其中求和跑遍全部类别。
这类题属于算法机考高频题型中「华为 AI 岗 / F1」方向的高频题型,通常考察对「华为 AI 岗 / F1」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入 n k。第二行 n 个整数,表示真实标签。第三行 n 个整数,表示预测标签。
输出 k 行,第 c 行是类别 c 的 precision recall F1,各按四舍五入保留 4 位小数;最后再输出一行 macroF1 microF1,各按四舍五入保留 6 位小数,用单个空格分隔。
1 <= n <= 80000;2 <= k <= 10;所有标签都在 [0, k) 内。
示例 1
输入示例
8 3 0 0 1 1 2 2 0 1 0 1 1 1 2 0 0 2
输出示例
0.6667 0.6667 0.6667 0.6667 0.6667 0.6667 0.5000 0.5000 0.5000 0.611111 0.625000
三分类的一次评估
示例 2
输入示例
6 2 1 0 1 1 0 0 1 0 0 1 0 1
输出示例
0.6667 0.6667 0.6667 0.6667 0.6667 0.6667 0.666667 0.666667
二分类退化
时间限制 2000 ms · 内存限制 256 MB
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
这些是真正决定能不能 AC、但通用题解里常被略过的点。
把混淆矩阵四格延伸到多分类:每个类各算一遍 P/R/F1,再用两种方式汇总。宏平均和微平均的区别是评估岗面试的常客,这道题让你把两种口径都亲手算一遍,以后被问到就不是背答案了。
对类别 c:TP[c] = 真实和预测都是 c;FP[c] = 预测是 c 但真实不是;FN[c] = 真实是 c 但预测不是。实现上扫一遍样本就够:真实 == 预测时给 TP[真实] 加一;不等时给 FP[预测] 和 FN[真实] 各加一。O(n + k) 收工,n ≤ 8 万也毫无压力。
precision 的分母 TP+FP 为 0(这个类从没被预测过)、recall 的分母 TP+FN 为 0(数据里没这个类的真实样本)、F1 的分母 2TP+FP+FN 为 0(两者皆无)——一律按 0 输出。这是课程第 12 天的口径,写一个「分母为零返回 0」的小函数,三处复用。
前 k 行每行三个数保留 4 位,最后一行两个数保留 6 位。两种精度别串,这是格式分,丢了冤枉。
参考实现三个长度为 k 的数组计数,一遍扫完样本;一个 safe_div(a, b) 小函数统一处理 0/0;宏平均循环全部 k 个类求 F1 均值,微平均对三个数组分别求和再套一次 F1 公式。全程 O(n + k),n = 8 万瞬间跑完。
1. 全对(预测 == 真实):每个出现过的类 P = R = F1 = 1,微平均 = 1.000000;没出现的类是 0,宏平均被幽灵类拉低——这正是宏/微的分岔现场。 2. k = 3 但数据里只有类 0、1:类 2 一行输出 0.0000 0.0000 0.0000,且宏平均分母仍是 3。 3. 微平均 = 准确率:数出预测对的样本数除以 n,和你的微平均 F1 对一下,不等就是计数错了。
按这三组过一遍,四格计数和两种平均的口径就都验证到了。
这是第 12 天评估口径的多分类延伸:那天的二分类四格在这里变成 k 套,0/0 按 0 的约定原样沿用。面试里被追问「宏平均和微平均什么时候差别大」,答案就在幽灵类和类不平衡里——少数类表现差时宏平均掉得快,微平均被多数类托着;这道题的倾斜用例就是现成的演示数据。
# 所有指标保留为整数分数,并用整数实现十进制 half-up;宏平均用 Fraction 精确求和。
import sys
from fractions import Fraction
def format_fraction(num, den, digits):
if den == 0:
num, den = 0, 1
scale = 10 ** digits
rounded = (2 * num * scale + den) // (2 * den)
return f"{rounded // scale}.{rounded % scale:0{digits}d}"
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
n, k = data[0], data[1]
truth = data[2:2 + n]
prediction = data[2 + n:2 + 2 * n]
tp = [0] * k
fp = [0] * k
fn = [0] * k
for actual, predicted in zip(truth, prediction):
if actual == predicted:
tp[actual] += 1
else:
fp[predicted] += 1
fn[actual] += 1
lines = []
macro_sum = Fraction(0, 1)
for c in range(k):
p_den = tp[c] + fp[c]
r_den = tp[c] + fn[c]
f_den = 2 * tp[c] + fp[c] + fn[c]
lines.append(" ".join((
format_fraction(tp[c], p_den, 4),
format_fraction(tp[c], r_den, 4),
format_fraction(2 * tp[c], f_den, 4),
)))
if f_den:
macro_sum += Fraction(2 * tp[c], f_den)
macro = macro_sum / k
total_tp, total_fp, total_fn = sum(tp), sum(fp), sum(fn)
micro_den = 2 * total_tp + total_fp + total_fn
lines.append(f"{format_fraction(macro.numerator, macro.denominator, 6)} {format_fraction(2 * total_tp, micro_den, 6)}")
sys.stdout.write("\n".join(lines) + "\n")
main()
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有