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