Учёный решил провести кластеризацию некоторого множества звёзд по их расположению на карте звёздного неба. Кластер звёзд – это набор звёзд (точек) на графике, каждая из которых находится от хотя бы одной другой звезды на расстоянии не более условных единиц. Каждая звезда обязательно принадлежит только одному из кластеров.
Двойная система – это два объекта на расстоянии не более . При этом других звезд на расстоянии менее
у этих двух звезд быть не должно.
Под расстоянием понимается расстояние Евклида между двумя точками и
на плоскости, которое вычисляется по формуле:
Аномалиями назовём точки, находящиеся на расстоянии более одной условной единицы от точек кластеров. При расчётах аномалии учитывать не нужно.
В файле A хранятся данные о звёздах пяти кластеров, где ,
для каждого кластера. В каждой строке записана информация о расположении на карте одной звезды, а также ее масса (в солнечных массах): сначала координата
, затем координата
, затем масса
. Значения даны в условных единицах, которые представлены вещественными числами. В случае, если масса представлена положительным числом, объект является звездой, если отрицательным – объект является нейтронной звездой либо черной дырой. Известно, что количество звёзд не превышает 3000.
В файле Б хранятся данные о звёздах четырёх кластеров, где ,
для каждого кластера. Известно, что количество звёзд не превышает 10 000. Структура хранения информации о звездах в файле Б аналогична файлу А.
Для каждого файла в каждом кластере найдите двойную систему, состоящую из звезды и черной дыры с максимальной разницей масс. Масса нейтронной звезды не превышает 2.7 солнечных (по модулю), дальше — черные дыры. Затем вычислите два числа: – среднее арифметическое абсцисс найденных небесных тел, и
– среднее арифметическое ординат, найденных небесных тел.
В ответе запишите четыре числа через пробел: сначала целую часть произведения для файла А, затем
для файла А, далее целую часть произведения
для файла Б и
для файла Б.
Возможные данные одного из файлов иллюстрированы графиком.
Внимание! График приведён в иллюстративных целях для произвольных значений, не имеющих отношения к заданию. Для выполнения задания используйте данные из прилагаемого файла.
Для начала визуально оценим данные в условии кластеры. Для этого откроем предложенные файлы в , перейдем в раздел «Вставка
Диаграммы
Точечная».
Диаграмма для файла А имеет вид:
Диаграмма для файла Б имеет вид:
Для разделения звезд на кластеры будем использовать функцию dbscan.
Дальше основная идея решения будет заключаться в том, что мы будем проходить по каждой точке в пяти для файла А и четырех для файла Б найденных кластерах и с помощью того же метода dbscan для каждого кластера найти списки звезд, расстояние между которыми менее 0.2 для файла А и 0.02 для файла Б.
В каждом кластере нужно оставить только те списки, в которых количество звезд равно двум – то есть только двойные звездные системы. Также нужно проверить по массе звезд, чтобы в паре была звезда и черная дыра.
В конце остается дело за малым: для каждой звездной системы в каждом кластере найти пару с максимальной разницей масс между телами, а затем рассчитать среднее расстояние между всеми найденными парами.
Программа:
from math import *
def dbscan(a, r):
cl = [] # Инициализируем список для хранения кластеров
while a: # Пока есть элементы в входном массиве ’a’
# Создаем новый кластер и добавляем в него первый элемент из ’a’
cl.append([a.pop(0)])
for i in cl[-1]: # Проходим по элементам последнего кластера
# Проверяем каждый элемент ’j’ в оставшихся элементах ’a’
for j in a[:]:
# Если расстояние между ’i’ и ’j’ меньше радиуса ’r’
x = [i[0], i[1]]
y = [j[0], j[1]]
if dist(x, y) < r:
cl[-1].append(j) # Добавляем ’j’ в текущий кластер
a.remove(j) # Удаляем ’j’ из списка ’a’, чтобы не проверять его снова
return cl
f = open("2.txt")
s = f.readline()
a = [list(map(float, i.replace(",", ".").split())) for i in f]
cl = dbscan(a, 0.68) # для файла А
cl = dbscan(a, 0.55) # для файла Б
cl_total = []
for i in cl:
if len(i) > 10: cl_total.append(i)
t = 0.2 # для файла А
t = 0.02 # для файла Б
ans = []
for i in cl_total: # Проходим по каждому элементу в списке cl_total
found_star = dbscan(i, t) # Применяем алгоритм DBSCAN
bin_stars = [] # Список для бинарных систем
mx_starsys = [] # Список для хранения системы небесных тел с максимальной разницей масс
# Проходим по каждому кластеру, найденному алгоритмом DBSCAN
for j in found_star:
if len(j) == 2: # Проверяем, состоит ли кластер из двух тел
# Проверяем, что в паре есть черная дыра и обычная звезда
if (j[0][2] < -2.7 and j[1][2] > 0) or (j[1][2] < -2.7 and j[0][2] > 0):
bin_stars.append(j)
mx_mass = 0 # Переменная для хранения максимальной разницы масс
for j in bin_stars: # Проходим по всем найденным бинарным системам
# Вычисляем разницу между массами
if abs(abs(j[0][2]) - abs(j[1][2])) > mx_mass:
mx_mass = abs(abs(j[0][2]) - abs(j[1][2])) # Обновляем максимальную разницу
mx_starsys = j # Сохраняем текущую звездную систему как систему с максимальной разницей
ans.append(mx_starsys)
# Рассчитываем среднее значение
res_X = 0
res_Y = 0
for i in ans:
res_X += (i[0][0] + i[1][0])
res_Y += (i[0][1] + i[1][1])
print(int(res_X / (5 * 2) * 100)) # Для файла А
print(int(res_Y / (5 * 2) * 100)) # Для файла А
print(int(res_X / (4 * 2) * 100)) # Для файла Б
print(int(res_Y / (4 * 2) * 100)) # Для файла Б