通过率 60% · 提交 5 · 通过 3
这道 OJ 的配套动画
K-Means 聚类 · 对应本题的思路、过程和代码
给定 n 个 d 维样本、k 个初始聚类中心和迭代次数 t,完成固定 t 轮 K-Means 更新。
每轮先使用本轮开始时的全部中心,为每个样本计算到各中心的欧氏距离平方 d_i。令 d_min 为这些平方距离的最小值,在所有满足 d_i − d_min ≤ 10^-9 的中心中,选择编号最小者。中心编号从 1 开始。
全部样本分配完成后,非空簇的中心更新为簇内样本逐维均值;空簇沿用本轮开始时的中心。执行完 t 轮后按中心编号输出坐标。
这类题属于算法机考高频题型中「华为 AI 岗 / K-Means」方向的高频题型,通常考察对「华为 AI 岗 / K-Means」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入四个整数 n d k t。接下来 k 行,每行 d 个整数,表示初始聚类中心。随后 n 行,每行 d 个整数,表示一个样本。
输出 k 行,每行 d 个保留两位小数的实数,表示最终聚类中心。绝对值小于 0.0005 时输出 0.00。舍入后数值为零时统一输出 0.00。
1 <= n <= 2000;1 <= d <= 8;1 <= k <= min(n, 20);0 <= t <= 20;初始中心和样本坐标为 [-10000, 10000] 内整数。测试数据保证最终坐标不落在两位小数的舍入中点。
示例 1
输入示例
4 2 2 2 0 0 8 8 1 1 2 2 8 9 9 8
输出示例
1.50 1.50 8.50 8.50
两轮后两个簇分别稳定在左下和右上。
示例 2
输入示例
3 2 2 0 -3 4 7 -2 0 0 1 1 2 2
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
训练营动画视频讲解
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
输出示例
-3.00 4.00 7.00 -2.00
迭代次数为 0,直接输出初始中心。
时间限制 3000 ms · 内存限制 256 MB
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有
这些是真正决定能不能 AC、但通用题解里常被略过的点。
每轮先使用本轮开始时的全部中心完成样本分配,再统一更新中心;空簇保留原中心。由于初始坐标和样本均为整数,中心可保存为各维坐标和 S 与样本数 q,坐标值为 S/q。样本到中心的平方距离也表示为有理数,比较时通过交叉相乘完成,避免提前转换为浮点数。
分配阶段先求所有中心距离的全局最小值,再从与该最小值相差不超过 10^-9 的中心中选择最小编号,准确落实题目的容差规则。全部样本分配完成后才更新中心,因此一轮中的每次距离计算都使用同一组旧中心;非空簇取逐维均值,空簇保持不变,与 K-Means 的题目定义一致。
每轮需要计算 n 个样本到 k 个 d 维中心的距离,时间复杂度为 O(tnkd);保存样本、中心坐标和分组累计量需要 O(nd+kd) 空间。整数交叉乘法的位数在题目约束内可控。
t=0 时直接输出初始中心。容差必须相对于同一个全局最小距离,不能在遍历过程中逐个与“当前最优”做传递式淘汰。空簇沿用旧中心;最终输出使用精确商和余数完成两位小数舍入,并规范负零。
"""Exact global-minimum epsilon selection for integer-input K-Means."""
import sys
def select(point, centers, counts):
numerators = [sum((x*q-s)**2 for x,s in zip(point, row))
for row,q in zip(centers, counts)]
denominators = [q*q for q in counts]
best = 0
for i in range(1, len(centers)):
if numerators[i]*denominators[best] < numerators[best]*denominators[i]:
best = i
for i in range(len(centers)):
gap = numerators[i]*denominators[best] - numerators[best]*denominators[i]
if gap*10**9 <= denominators[i]*denominators[best]:
return i
def format_coordinate(total, count):
if abs(total)*2000 < count:
return '0.00'
value = (200*abs(total)+count)//(2*count)
return ('-' if total < 0 and value else '') + f'{value//100}.{value%100:02d}'
def solve(text):
data = iter(map(int, text.split()))
n,d,k,t = (next(data) for _ in range(4))
centers = [[next(data) for _ in range(d)] for _ in range(k)]
points = [[next(data) for _ in range(d)] for _ in range(n)]
counts = [1]*k
for _ in range(t):
sums = [[0]*d for _ in range(k)]
sizes = [0]*k
for point in points:
index = select(point, centers, counts)
sizes[index] += 1
for j in range(d):
sums[index][j] += point[j]
for i in range(k):
if sizes[i]:
centers[i], counts[i] = sums[i], sizes[i]
return '\n'.join(' '.join(format_coordinate(s,q) for s in row)
for row,q in zip(centers, counts))
if __name__ == '__main__':
print(solve(sys.stdin.read()))