27. Программирование: #299495
В файле $А$ хранятся данные о звёздах двух кластеров. В каждой строке записана информация о расположении на карте одной звезды: сначала координата $x$, затем координата $y$ (в условных единицах). Известно, что количество звёзд не превышает $1000$. В файле $Б$ хранятся данные о звёздах трёх кластеров. Известно, что количество звёзд не превышает $10,000$. Структура хранения информации о звездах в файле $Б$ аналогична файлу $А$. Возможные данные одного из файлов иллюстрированы графиком.
В ответе запишите четыре числа через запятую: сначала целую часть произведения $P_x \times 10,000$, затем целую часть произведения $P_y \times 10,000$ для файла $А$, далее — данные для файла $Б$.
Гарантируется, что во всех кластерах количество точек различно.
Обратите внимание на два места, где легко ошибиться. Во-первых, $P_x$ и $P_y$ берутся независимо друг от друга — это минимум по абсциссам и минимум по ординатам, а не координаты одной точки (здесь они случайно совпали, но полагаться на это нельзя). Во-вторых, $Q_2$ — это расстояние между центром одного кластера и точками другого: центр берётся у самого малочисленного кластера, а точки перебираются у самого многочисленного.
Центр определяется через сумму расстояний — это точка самого кластера, ищем её перебором, а не как среднее арифметическое координат.
Кластеризация. Кластеры разделены в пространстве, поэтому разбиваем точки на компоненты связности. Порог здесь надо подобрать аккуратно, особенно в файле $А$: точек всего $96$, они разрежены, и при пороге $0{,}5$ данные рассыпаются на девять кусков, а при $2{,}0$ два кластера уже сливаются в один. Рабочий диапазон — от $0{,}8$ до $1{,}5$. В файле $Б$ точек много ($9612$), и результат устойчив от $0{,}8$ до $2{,}0$: три группы по $3217$, $3205$ и $3190$ точек.
import zipfile, math
from xml.etree import ElementTree as ET
T = '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}'
O = '{urn:oasis:names:tc:opendocument:xmlns:office:1.0}'
def load(name):
x = ET.fromstring(zipfile.ZipFile(name).read('content.xml'))
P = []
for r in x.iter(T + 'table-row'):
parts = []
for c in r.iter(T + 'table-cell'):
v = c.get(O + 'value') or ''.join(c.itertext()).strip()
if v: parts.append(v)
tok = ' '.join(parts).replace(',', '.').split()
if len(tok) < 2: continue
try: P.append((float(tok[0]), float(tok[1])))
except ValueError: pass
return P
def center(c):
return min(c, key=lambda a: sum(math.dist(a, b) for b in c))
def clusters(pts, eps=1.0):
unused, res = set(range(len(pts))), []
while unused:
i = unused.pop(); comp, stack = [i], [i]
while stack:
a = stack.pop()
for j in list(unused):
if math.dist(pts[a], pts[j]) < eps:
unused.discard(j); comp.append(j); stack.append(j)
res.append([pts[k] for k in comp])
return res
A = load('27-25_А.ods')
cs = [center(c) for c in clusters(A)]
Px, Py = min(p[0] for p in cs), min(p[1] for p in cs)
print(int(abs(Px) * 10000), int(abs(Py) * 10000))
B = load('27-25_Б.ods')
cl = sorted(clusters(B), key=len)
c_min, c_max = center(cl[0]), center(cl[-1])
Q1 = math.dist(c_min, c_max)
Q2 = max(math.dist(c_min, p) for p in cl[-1]) # центр малого — точки большого
print(int(Q1 * 10000), int(Q2 * 10000))
Результаты для файла $А$. Всего $96$ точек, два кластера по $40$ и $56$ точек. Первый занимает область $x \in [-1{,}79;\ 0{,}89]$, $y \in [0{,}08;\ 2{,}61]$, его центр — $(-0{,}53072;\ 1{,}317191)$; второй занимает $x \in [1{,}41;\ 4{,}15]$, $y \in [3{,}40;\ 6{,}07]$ с центром $(2{,}678363;\ 4{,}828825)$. Минимальная абсцисса $P_x = -0{,}53072$, минимальная ордината $P_y = 1{,}317191$, что после умножения на $10,000$ и отбрасывания дробной части даёт $5307$ и $13171$.
Результаты для файла $Б$. Всего $9612$ точек, три кластера по $3217$, $3205$ и $3190$ точек с центрами $(1{,}275163;\ 1{,}285489)$, $(3{,}312774;\ 8{,}70916)$ и $(6{,}665161;\ 5{,}41046)$ соответственно. Самый малочисленный кластер — из $3190$ точек с центром $(6{,}665161;\ 5{,}41046)$, самый многочисленный — из $3217$ точек с центром $(1{,}275163;\ 1{,}285489)$.
Расстояние между этими центрами $Q_1 = 6{,}7873017$. Максимальное удаление точки большого кластера от центра малого $Q_2 = 7{,}8569441$. Умножаем на $10,000$ и берём целые части: $67873$ и $78569$.