Лосяш решил исследовать звёздное небо над Долиной Смешариков. Он провёл кластеризацию множества звёзд по их расположению на трёхмерной карте. Кластер звёзд — это набор точек на графике, каждая из которых находится от хотя бы одной другой звезды на расстоянии не более условных единиц. Каждая звезда принадлежит только одному кластеру.
Истинный центр кластера, или центроид, — это одна из звёзд, сумма расстояний от которой до всех остальных звёзд кластера минимальна.
Расстояние между двумя точками и
в трёхмерном пространстве вычисляется по формуле Евклида:
Аномалиями называются точки, расположенные на расстоянии более одной условной единицы от всех точек кластеров. Аномалии в расчётах учитывать не нужно.
В файле A хранятся данные о звёздах трёх кластеров, где для каждого кластера. В каждой строке записаны координаты одной звезды:
, затем
, затем
. Значения даны в условных единицах как вещественные числа. Количество звёзд не превышает 1200.
В файле B хранятся данные о звёздах двух кластеров, где для каждого кластера. Количество звёзд не превышает 5200. Структура данных в файле B аналогична файлу A.
Для каждого файла определите координаты центроида каждого кластера, затем вычислите одно число: — квадрат произведения средних арифметических абсцисс, ординат и аппликат центроидов кластеров.
В ответе запишите два числа через пробел: сначала целую часть частного для файла A, затем целую часть произведения
для файла B.
Внимание! График приведён в иллюстративных целях для произвольных значений и не относится к заданию. Используйте данные из прилагаемого файла.
Для начала визуально оценим данные в условиях кластеров. Откроем файлы в , перейдём в раздел «Вставка
Диаграммы
Точечная». Это позволит построить двухмерную проекцию кластеров на ось
, что достаточно для примерного понимания их положения в пространстве.
Диаграмма для файла A имеет вид:
Диаграмма для файла B имеет вид:
Для разделения звёзд на кластеры используем алгоритм DBSCAN с соответствующими радиусами. Затем для каждого кластера определим центроид, вычислив сумму расстояний от каждой звезды до остальных и выбрав звезду с минимальной суммой. После этого рассчитаем как квадрат произведения средних координат центроидов.
Код для файла A:
from math import *
def dbscan(a, r):
cl = [] # Инициализируем список для хранения кластеров
while a: # Пока есть элементы в входном массиве ’a’
cl.append([a.pop(0)])
for i in cl[-1]: # Проходим по элементам последнего кластера
for j in a[:]:
if dist(i, j) <= r:
cl[-1].append(j) # Добавляем ’j’ в текущий кластер
a.remove(j) # Удаляем ’j’ из списка ’a’, чтобы не проверять его снова
return cl
f = open("3_A.txt")
a = [list(map(float, i.replace(",", ".").split())) for i in f]
cl = dbscan(a, 1.5) # Для файла А
cl_total = []
for i in cl:
if len(i) > 50: cl_total.append(i)
sum_x = sum_y = sum_z = 0
for cluster in cl_total:
tx = ty = tz = 0
mn = 10 ** 20
for centroid in cluster:
sm = 0
for star in cluster:
sm += dist(centroid, star)
if sm < mn:
mn = sm
tx, ty, tz = centroid[0], centroid[1], centroid[2]
sum_x += tx
sum_y += ty
sum_z += tz
print(int(((sum_x / 3 * sum_y / 3 * sum_z / 3) ** 2) / 5))
Код для файла B:
from math import *
def dbscan(a, r):
cl = [] # Инициализируем список для хранения кластеров
while a: # Пока есть элементы в входном массиве ’a’
cl.append([a.pop(0)])
for i in cl[-1]: # Проходим по элементам последнего кластера
for j in a[:]:
if dist(i, j) <= r:
cl[-1].append(j) # Добавляем ’j’ в текущий кластер
a.remove(j) # Удаляем ’j’ из списка ’a’, чтобы не проверять его снова
return cl
f = open("3_B.txt")
a = [list(map(float, i.replace(",", ".").split())) for i in f]
cl = dbscan(a, 0.7)
cl_total = []
for i in cl:
if len(i) > 10: cl_total.append(i)
sum_x = sum_y = sum_z = 0
for cluster in cl_total:
tx = ty = tz = 0
mn = 10 ** 20
for centroid in cluster:
sm = 0
for star in cluster:
sm += dist(centroid, star)
if sm < mn:
mn = sm
tx, ty, tz = centroid[0], centroid[1], centroid[2]
sum_x += tx
sum_y += ty
sum_z += tz
print(int(((sum_x / 2 * sum_y / 2 * sum_z / 2) ** 2) * 50))