* 4.8_01
This commit is contained in:
parent
e96d20343b
commit
c22ef9e724
@ -12,7 +12,8 @@ Link - для описания связи между двумя произвол
|
||||
LinkedGraph - для представления связного графа в целом (карта целиком).
|
||||
|
||||
Объекты класса Vertex должны создаваться командой:
|
||||
v = Vertex()
|
||||
>>> v = Vertex()
|
||||
|
||||
и содержать локальный атрибут:
|
||||
_links - список связей с другими вершинами графа (список объектов класса Link).
|
||||
|
||||
@ -20,7 +21,9 @@ _links - список связей с другими вершинами граф
|
||||
links - для получения ссылки на список _links.
|
||||
|
||||
Объекты следующего класса Link должны создаваться командой:
|
||||
link = Link(v1, v2)
|
||||
>>> v1 = Vertex(); v2 = Vertex()
|
||||
>>> link = Link(v1, v2)
|
||||
|
||||
где v1, v2 - объекты класса Vertex (вершины графа). Внутри каждого объекта класса Link должны формироваться следующие локальные атрибуты:
|
||||
|
||||
_v1, _v2 - ссылки на объекты класса Vertex, которые соединяются данной связью;
|
||||
@ -32,7 +35,7 @@ v2 - для получения ссылки на вершину v2;
|
||||
dist - для изменения и считывания значения атрибута _dist.
|
||||
|
||||
Наконец, объекты третьего класса LinkedGraph должны создаваться командой:
|
||||
map_graph = LinkedGraph()
|
||||
>>> map_graph = LinkedGraph()
|
||||
|
||||
В каждом объекте класса LinkedGraph должны формироваться локальные атрибуты:
|
||||
_links - список из всех связей графа (из объектов класса Link);
|
||||
@ -58,30 +61,29 @@ _links = [Link(v1, v2)]
|
||||
|
||||
Пример использования классов, применительно к схеме метро (эти строчки в программе писать не нужно):
|
||||
|
||||
map_graph = LinkedGraph()
|
||||
|
||||
v1 = Vertex()
|
||||
v2 = Vertex()
|
||||
v3 = Vertex()
|
||||
v4 = Vertex()
|
||||
v5 = Vertex()
|
||||
v6 = Vertex()
|
||||
v7 = Vertex()
|
||||
|
||||
map_graph.add_link(Link(v1, v2))
|
||||
map_graph.add_link(Link(v2, v3))
|
||||
map_graph.add_link(Link(v1, v3))
|
||||
|
||||
map_graph.add_link(Link(v4, v5))
|
||||
map_graph.add_link(Link(v6, v7))
|
||||
|
||||
map_graph.add_link(Link(v2, v7))
|
||||
map_graph.add_link(Link(v3, v4))
|
||||
map_graph.add_link(Link(v5, v6))
|
||||
|
||||
print(len(map_graph._links)) # 8 связей
|
||||
print(len(map_graph._vertex)) # 7 вершин
|
||||
path = map_graph.find_path(v1, v6)
|
||||
>>> Vertex._num = 0
|
||||
>>> map_graph = LinkedGraph()
|
||||
>>> v1 = Vertex()
|
||||
>>> v2 = Vertex()
|
||||
>>> v3 = Vertex()
|
||||
>>> v4 = Vertex()
|
||||
>>> v5 = Vertex()
|
||||
>>> v6 = Vertex()
|
||||
>>> v7 = Vertex()
|
||||
>>> map_graph.add_link(Link(v1, v2))
|
||||
>>> map_graph.add_link(Link(v2, v3))
|
||||
>>> map_graph.add_link(Link(v1, v3))
|
||||
>>> map_graph.add_link(Link(v4, v5))
|
||||
>>> map_graph.add_link(Link(v6, v7))
|
||||
>>> map_graph.add_link(Link(v2, v7))
|
||||
>>> map_graph.add_link(Link(v3, v4))
|
||||
>>> map_graph.add_link(Link(v5, v6))
|
||||
>>> len(map_graph._links)
|
||||
8
|
||||
>>> len(map_graph._vertex)
|
||||
7
|
||||
>>> map_graph.find_path(v1, v6)
|
||||
([Vertex('A'), Vertex('B'), Vertex('G'), Vertex('F')], [Link(Vertex('A'), Vertex('B'), 1), Link(Vertex('B'), Vertex('G'), 1), Link(Vertex('F'), Vertex('G'), 1)])
|
||||
|
||||
Однако, в таком виде применять классы для схемы карты метро не очень удобно.
|
||||
Например, здесь нет указаний названий станций, а также длина каждого сегмента равна 1, что не соответствует действительности.
|
||||
@ -91,7 +93,8 @@ class Station(Vertex): ... - для описания станций метро;
|
||||
class LinkMetro(Link): ... - для описания связей между станциями метро.
|
||||
|
||||
Объекты класса Station должны создаваться командой:
|
||||
st = Station(name)
|
||||
>>> st = Station(name := "Домодедовская")
|
||||
|
||||
где name - название станции (строка). В каждом объекте класса Station должен дополнительно формироваться локальный атрибут:
|
||||
name - название станции метро.
|
||||
|
||||
@ -99,37 +102,42 @@ name - название станции метро.
|
||||
В самом классе Station переопределите магические методы __str__() и __repr__(), чтобы они возвращали название станции метро (локальный атрибут name).
|
||||
|
||||
Объекты второго класса LinkMetro должны создаваться командой:
|
||||
link = LinkMetro(v1, v2, dist)
|
||||
>>> link = LinkMetro(v1, v2, dist := 2)
|
||||
|
||||
где v1, v2 - вершины (станции метро); dist - расстояние между станциями (любое положительное число).
|
||||
(Также не забывайте в инициализаторе этого дочернего класса вызывать инициализатор базового класса).
|
||||
|
||||
В результате, эти классы должны совместно работать следующим образом (эти строчки в программе писать не нужно):
|
||||
|
||||
map_metro = LinkedGraph()
|
||||
v1 = Station("Сретенский бульвар")
|
||||
v2 = Station("Тургеневская")
|
||||
v3 = Station("Чистые пруды")
|
||||
v4 = Station("Лубянка")
|
||||
v5 = Station("Кузнецкий мост")
|
||||
v6 = Station("Китай-город 1")
|
||||
v7 = Station("Китай-город 2")
|
||||
>>> map_metro = LinkedGraph()
|
||||
>>> v1 = Station("Сретенский бульвар")
|
||||
>>> v2 = Station("Тургеневская")
|
||||
>>> v3 = Station("Чистые пруды")
|
||||
>>> v4 = Station("Лубянка")
|
||||
>>> v5 = Station("Кузнецкий мост")
|
||||
>>> v6 = Station("Китай-город 1")
|
||||
>>> v7 = Station("Китай-город 2")
|
||||
|
||||
map_metro.add_link(LinkMetro(v1, v2, 1))
|
||||
map_metro.add_link(LinkMetro(v2, v3, 1))
|
||||
map_metro.add_link(LinkMetro(v1, v3, 1))
|
||||
>>> map_metro.add_link(LinkMetro(v1, v2, 1))
|
||||
>>> map_metro.add_link(LinkMetro(v2, v3, 1))
|
||||
>>> map_metro.add_link(LinkMetro(v1, v3, 1))
|
||||
|
||||
map_metro.add_link(LinkMetro(v4, v5, 1))
|
||||
map_metro.add_link(LinkMetro(v6, v7, 1))
|
||||
>>> map_metro.add_link(LinkMetro(v4, v5, 1))
|
||||
>>> map_metro.add_link(LinkMetro(v6, v7, 1))
|
||||
|
||||
map_metro.add_link(LinkMetro(v2, v7, 5))
|
||||
map_metro.add_link(LinkMetro(v3, v4, 3))
|
||||
map_metro.add_link(LinkMetro(v5, v6, 3))
|
||||
>>> map_metro.add_link(LinkMetro(v2, v7, 5))
|
||||
>>> map_metro.add_link(LinkMetro(v3, v4, 3))
|
||||
>>> map_metro.add_link(LinkMetro(v5, v6, 3))
|
||||
|
||||
print(len(map_metro._links))
|
||||
print(len(map_metro._vertex))
|
||||
path = map_metro.find_path(v1, v6) # от сретенского бульвара до китай-город 1
|
||||
print(path[0]) # [Сретенский бульвар, Тургеневская, Китай-город 2, Китай-город 1]
|
||||
print(sum([x.dist for x in path[1]])) # 7
|
||||
>>> print(len(map_metro._links))
|
||||
8
|
||||
>>> print(len(map_metro._vertex))
|
||||
7
|
||||
>>> path = map_metro.find_path(v1, v6) # от сретенского бульвара до китай-город 1
|
||||
>>> print(path[0]) # [Сретенский бульвар, Тургеневская, Китай-город 2, Китай-город 1]
|
||||
[Сретенский бульвар, Тургеневская, Китай-город 2, Китай-город 1]
|
||||
>>> print(sum([x.dist for x in path[1]])) # 7
|
||||
7
|
||||
|
||||
P.S. В программе нужно объявить только классы Vertex, Link, LinkedGraph, Station, LinkMetro. На экран ничего выводить не нужно.
|
||||
"""
|
||||
@ -137,7 +145,7 @@ P.S. В программе нужно объявить только классы
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from functools import total_ordering
|
||||
from typing import List, Union
|
||||
from typing import List, Optional, Tuple, Union
|
||||
|
||||
|
||||
def make_properties_prot(*names):
|
||||
@ -159,12 +167,14 @@ def make_properties_prot(*names):
|
||||
|
||||
|
||||
class AutoNamed:
|
||||
_num = 0
|
||||
_num: int = 0
|
||||
name: str
|
||||
|
||||
@staticmethod
|
||||
def column_code(num):
|
||||
def gen(n):
|
||||
def column_code(num: int) -> str:
|
||||
"""Имя как код колонки в Excel по порядковому номеру с 1"""
|
||||
|
||||
def gen(n: int):
|
||||
a = ord("A")
|
||||
sz = ord("Z") - a + 1
|
||||
while n:
|
||||
@ -182,7 +192,7 @@ class AutoNamed:
|
||||
|
||||
@make_properties_prot("links")
|
||||
class Vertex(AutoNamed):
|
||||
def __init__(self, name=None):
|
||||
def __init__(self, name: Optional[str] = None):
|
||||
if name:
|
||||
self.name = name
|
||||
self._links = []
|
||||
@ -238,7 +248,7 @@ class LinksPath:
|
||||
return sum([x.dist for x in self.links])
|
||||
return float("inf")
|
||||
|
||||
def add_link(self, link):
|
||||
def add_link(self, link: Link):
|
||||
if link not in self.links:
|
||||
self.links.append(link)
|
||||
return self
|
||||
@ -263,52 +273,51 @@ class LinksPath:
|
||||
|
||||
@make_properties_prot("links", "vertex")
|
||||
class LinkedGraph:
|
||||
def __init__(self, vertex=None, links=None):
|
||||
def __init__(self, vertex: Optional[Vertex] = None, links: Optional[Link] = None):
|
||||
self._vertex = vertex or []
|
||||
self._links = links or []
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}{(self.vertex, self.links)!r}"
|
||||
|
||||
def add_vertex(self, v):
|
||||
def add_vertex(self, v: Vertex):
|
||||
if v not in self._vertex:
|
||||
self._vertex.append(v)
|
||||
|
||||
def add_link(self, link):
|
||||
def add_link(self, link: Link):
|
||||
if link not in self._links:
|
||||
self._links.append(link)
|
||||
for v in link:
|
||||
self.add_vertex(v)
|
||||
|
||||
def dijkstras(self, start, stop=None):
|
||||
def dijkstras(self, start: Vertex, stop: Optional[Vertex] = None):
|
||||
def walk(remaining, paths, current):
|
||||
while remaining:
|
||||
remaining.discard(current)
|
||||
yield current
|
||||
if current == stop:
|
||||
break
|
||||
if remaining:
|
||||
current = min(remaining, key=lambda x: paths[x])
|
||||
|
||||
paths = defaultdict(LinksPath)
|
||||
paths[start].is_start = True
|
||||
remaining, current = set(self.vertex), start
|
||||
while remaining:
|
||||
remaining.discard(current)
|
||||
remaining = set(self.vertex)
|
||||
for current in walk(remaining, paths, start):
|
||||
for link in current:
|
||||
for v in link:
|
||||
if v not in remaining:
|
||||
continue
|
||||
for v in filter(lambda v: v in remaining, link):
|
||||
new_path = paths[current].copy().add_link(link)
|
||||
if new_path < paths[v]:
|
||||
paths[v] = new_path
|
||||
if current == stop:
|
||||
break
|
||||
if remaining:
|
||||
current = min(remaining, key=lambda x: paths[x])
|
||||
paths[v] = min(paths[v], new_path)
|
||||
return paths
|
||||
|
||||
def find_path(self, start_v, stop_v):
|
||||
def find_path(
|
||||
self, start_v: Vertex, stop_v: Vertex
|
||||
) -> Tuple[List[Vertex], List[Link]]:
|
||||
path = self.dijkstras(start_v, stop_v)[stop_v]
|
||||
return path.vertex, path.links
|
||||
|
||||
|
||||
class Station(Vertex):
|
||||
def __init__(self, name: str):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
@ -317,14 +326,9 @@ class LinkMetro(Link):
|
||||
...
|
||||
|
||||
|
||||
vA = Vertex("A")
|
||||
vB = Vertex("B")
|
||||
vC = Vertex("C")
|
||||
vD = Vertex("D")
|
||||
vE = Vertex("E")
|
||||
vF = Vertex("F")
|
||||
vG = Vertex("G")
|
||||
print("-------------------------------------------")
|
||||
|
||||
vA, vB, vC, vD, vE, vF, vG = [Vertex() for _ in range(7)]
|
||||
map_graph = LinkedGraph()
|
||||
map_graph.add_link(Link(vA, vB))
|
||||
map_graph.add_link(Link(vB, vC))
|
||||
@ -340,6 +344,7 @@ map_graph.add_link(Link(vE, vF))
|
||||
print(len(map_graph._links)) # 8 связей
|
||||
print(len(map_graph._vertex)) # 7 вершин
|
||||
print(map_graph.find_path(vA, vG))
|
||||
# ([Vertex('A'), Vertex('B'), Vertex('G')], [Link(Vertex('A'), Vertex('B'), 1), Link(Vertex('B'), Vertex('G'), 1)])
|
||||
|
||||
print("-------------------------------------------")
|
||||
|
||||
@ -370,6 +375,7 @@ print(path[0]) # [Сретенский бульвар, Тургеневская
|
||||
print(sum([x.dist for x in path[1]])) # 7
|
||||
|
||||
print("-------------------------------------------", flush=True)
|
||||
Vertex._num = 0 # naming reset
|
||||
|
||||
# exit(1)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user