Фрагмент звёздного неба спроецирован на плоскость с декартовой системой координат. Учёный решил провести кластеризацию полученных точек, являющихся изображениями звёзд, то есть разбить их множество на N непересекающихся непустых подмножеств (кластеров), таких что точки каждого подмножества лежат внутри прямоугольника со сторонами длиной H и W, причём эти прямоугольники между собой не пересекаются. Стороны прямоугольников не обязательно параллельны координатным осям.
Гарантируется, что такое разбиение существует и единственно для заданных размеров прямоугольников.
Гарантируется, что во всех кластерах количество точек различно.
Для каждой звезды задана характеристика — набор символов, включающий спектральный класс (обозначается латинской буквой), подкласс светимости (обозначается арабской цифрой) и класс светимости (обозначается римской цифрой).
Спектральный класс звезды определяется в соответствии с таблицей:
| Спектральный класс звезды | ||||||
|---|---|---|---|---|---|---|
| O | B | A | F | G | K | M |
| Голубая | Бело-голубая | Белая | Жёлто-белая | Жёлтая | Оранжевая | Красная |
Класс светимости звезды определяется в соответствии с таблицей:
| Класс светимости звезды | ||||||
|---|---|---|---|---|---|---|
| I | II | III | IV | V | VI | VII |
| сверхгигант | яркий гигант | гигант | субгигант | карлик | субкарлик | квазар |
Будем называть центром кластера точку этого кластера, сумма расстояний от которой до всех остальных точек кластера минимальна. Для каждого кластера гарантируется единственность его центра. Расстояние между двумя точками на плоскости А(х1, y1) и B(х2, y2) вычисляется по формуле:
В файле А хранятся данные о звёздах двух кластеров, где Н = 5 и W = 4 для каждого кластера. В каждой строке записана информация одной звезды: координата х, координата у и её характеристика. Значения даны в условных единицах. Известно, что количество точек не превышает 1000.
В файле Б хранятся данные о звёздах трёх кластеров, где Н = 3 и W = 5 для каждого кластера. Известно, что количество точек не превышает 10 000.
Структура хранения информации о звёздах в файле Б аналогична структуре в файле А.
Для файла А определите координаты центра каждого кластера, затем найдите два числа: A1 — абсциссу ближайшего белого гиганта к центру кластера с наименьшим количеством точек, и A2 — ординату ближайшего белого гиганта к центру кластера с наименьшим количеством точек.
Для файла Б определите координаты центра каждого кластера, затем найдите два числа: B1 — расстояние между центрами кластеров с наибольшим и наименьшим количеством красных сверхгигантов, и B2 — максимальное расстояние между двумя жёлтыми карликами, находящимися в одном кластере.
В ответе запишите четыре числа: в первой строке — сначала целую часть произведения A1 × 10 000, затем целую часть произведения A2 × 10 000; во второй строке — сначала целую часть произведения B1 × 10 000, затем целую часть произведения B2 × 10 000.
Ответ:
Построим диаграмму для файла А и В. Для этого откроем файлы с помощью python.
График для файла А:
График для файла В:
Приведём решение для файла А и B на языке Python.
import tkinter as tk
import math
all_stars = []
with open('27_B.txt') as f:
for line in f:
line = line.replace(',', '.').strip()
parts = line.split()
# Читаем координаты и тип
raw_x = float(parts[0])
raw_y = float(parts[1])
info = parts[2]
all_stars.append((raw_x, raw_y, info))
#Находим экстремумы для жесткого масштабирования
if all_stars:
xs = [s[0] for s in all_stars]
ys = [s[1] for s in all_stars]
min_x, max_x = min(xs), max(xs)
min_y, max_y = min(ys), max(ys)
# Задаем фиксированный размер окна
W, H = 1000, 700
pad = 50 # Отступ от краев, чтобы точки не прилипали к рамке
# Защита от деления на ноль, если все координаты одинаковые
dx = (max_x - min_x) if max_x != min_x else 1
dy = (max_y - min_y) if max_y != min_y else 1
# Рассчитываем SCALE
SCALE_X = (W - 2 * pad) / dx
SCALE_Y = (H - 2 * pad) / dy
SCALE = min(SCALE_X, SCALE_Y)
print(f"[+] Границы данных: X от {min_x} до {max_x}, Y от {min_y} до {max_y}")
print(f"[+] Вычисленный масштаб отрисовки (SCALE): {round(SCALE, 4)}")
else:
min_x, min_y, SCALE, pad, W, H = 0, 0, 1, 50, 1000, 700
# Перевод в пиксели
def to_px(rx, ry):
px = (rx - min_x) * SCALE + pad
py = H - ((ry - min_y) * SCALE + pad) # Инверсия Y для нормальной декартовой сетки
return px, py
# Клик-обработчик
def click_handler(event):
if not all_stars: return
# Переводим пиксели клика обратно в математику файла
cx = min_x + (event.x - pad) / SCALE
cy = min_y + (H - event.y - pad) / SCALE
closest = None
min_d = float('inf')
for star in all_stars:
rx, ry, info = star
d = math.hypot(cx - rx, cy - ry)
if d < min_d:
min_d = d
closest = star
rx, ry, info = closest
print(f"+ Клик мышкой по экрану в пикселях: ({event.x}, {event.y})")
print(f"* Ближайшая к клику реальная звезда: X = {rx}, Y = {ry}, Тип = {info}")
print("-" * 50)
# 3. Графический интерфейс Tkinter
root = tk.Tk()
root.title("Кликер Кластеров")
canvas = tk.Canvas(root, width=W, height=H, bg='black')
canvas.pack()
canvas.bind("<1>", click_handler)
# Отрисовка
for rx, ry, info in all_stars:
px, py = to_px(rx, ry)
color = 0
#print(info[0], info[2:])
# Цветовая подсветка
if 'A' == info[0] and 'III' == info[2:]:
color = 'white'
elif 'M' == info[0] and 'I' == info[2:]:
color = 'red'
elif 'G' == info[0] and 'V' == info[2:]:
color = 'yellow'
# Можно тегать для удобства убирая лишние звёзды
else:
color = '#444444' # Обычные серые фоновые звезды
# Рисуем жирные, заметные квадраты 2х2 пикселя
if color:
canvas.create_rectangle(px-1, py-1, px+1, py+1, fill=color, outline=color)
# Для файла A
#border_y = 35
#cluster_1 = [s for s in all_stars if s[1] < border_y]
#cluster_2 = [s for s in all_stars if s[1] > border_y]
#target_cluster = cluster_1 if len(cluster_1) < len(cluster_2) else cluster_2
# Для файла B
cluster_1 = [s for s in all_stars if 7 < s[1] < 12.5]
cluster_2 = [s for s in all_stars if s[1] < 7]
def best_centroid(target_cluster):
best_center = None
min_sum = float('inf')
for cx, cy, _ in target_cluster:
curr_sum = sum(math.hypot(cx - px, cy - py) for px, py, _ in target_cluster)
if curr_sum < min_sum:
min_sum = curr_sum
best_center = (cx, cy)
print(best_center)
# Для файла A
#best_centroid(target_cluster)
# Ответы A1 и A2
#print(int(39.02054737781699 * 10**4))
#print(int(18.269948438629243 * 10**4))
# Для файла B
best_centroid(cluster_1), best_centroid(cluster_2)
# Ответы B1 и B2
print(int(((abs( 23.55819983673737 - 22.298551302558078))**2 + (abs(11.207801969160332 - 5.310152626026702))**2)**0.5 * 10**4))
print(int(((abs(22.32521100897972 - 23.194249781245507))**2 + (abs(16.329963528862102 - 17.72793552467998))**2)**0.5 * 10**4))
root.mainloop()
Ответ: 390205 182699 60306 16460.

