import sys import math def cal_dis(point1,point2): dim = len(point1) sum_up = 0 for i in range(dim): sum_up += (point1[i]-point2[i])**2 return math.sqrt(sum_up) def get_neighbors(samples,ind,eps): neighbors = [] for i in range(len(samples)): dis = cal_dis(samples[i],samples[ind]) if dis <= eps: neighbors.append(i) return neighbors def DBSCAN(eps,min_samples,x,samples): #使用一个列表core_points,表示每个点是否为核心点,0为非核心点,1为核心点,初始化为0 #使用一个列表label_ind,表示每个点的簇的下标,初始化为-2,表示未访问,-1为噪声,其他值表示簇的下标。 core_points = [0 for i in range(x)] label_ind = [-2 for i in range(x)] cluster_id = 0 for i in range(x): if label_ind[i] != -2: #已经访问过此点,直接下一个 continue neighbors = get_neighbors(samples,i,eps) if len(neighbors) < min_samples: label_ind[i] = -1 else: points_set = list(neighbors) #表示需要扩展的点集 points_set.remove(i) #删除点自身 label_ind[i] = cluster_id #更新此点簇的序号 core_points[i] = 1 #此点为核心点 j = 0 while j < len(points_set): #对于需要扩展的点 point_ind = points_set[j] if label_ind[point_ind] == -1: #为噪声,不扩展 label_ind[point_ind] = cluster_id elif label_ind[point_ind] == -2: #关键在于此处,不断更新需要扩展的点集 #如果当前点未被访问过,判断是否为核心点,如果是,则更新需要扩展的点的集合,并且只将未被访问过的点或者噪声点加入 label_ind[point_ind] = cluster_id point_neighbor = get_neighbors(samples,point_ind,eps) if len(point_neighbor) >= min_samples: core_points[point_ind] = 1 for neighbor_ind in point_neighbor: if label_ind[neighbor_ind] == -2 or label_ind[neighbor_ind] == -1: if neighbor_ind not in points_set: points_set.append(neighbor_ind) j += 1 cluster_id += 1 noise_count = label_ind.count(-1) cluster_num = len(set(label_ind))-(1 if -1 in label_ind else 0) return cluster_num,noise_count if __name__ == '__main__': lines = [] while True: try: line = input().split() if line: lines.append(line) else: break except EOFError: break eps, min_samples, x = float(lines[0][0]), int(lines[0][1]), int(lines[0][2]) samples = [ (float(lines[i][0]),float(lines[i][1])) for i in range(1,len(lines))] cluster_num, noise_count = DBSCAN(eps, min_samples, x, samples) print(cluster_num,noise_count)