Professional Documents
Culture Documents
Теорія а. №2
Теорія а. №2
Лабораторна робота №2
по курсу “Теорія алгоритмів”
на тему “Методи розробки алгоритмів. Частина 1.”
Варіант 7
2023
Комп’ютерний практикум 3
Тема: Методи розробки алгоритмів. Частина 1.
Мета роботи: Порівняння алгоритмів розв’язку задачі, побудованих
різними методами.
-Звіт-
Завдання
1. Для свого варіанту зробити наступні дії:
1) Сформулювати постановку задачі
2) Обрати відповідні 2 алгоритми з теоретичної частини практикуму або
на свій розсуд
3) Накреслити блок-схеми, на яких виконано аналіз складності алгоритмів
4) Написати програмний код
5) Провести дослідження продуктивності роботи алгоритмів, зробити
результати дослідження у вигляді графіків та діаграм;
6) Зробити висновки про доцільність використання кожного з алгоритмів
для типових вхідних даних та про відповідність результатів
експериментального дослідження аналітичним оцінкам складності.
7) Скласти таблицю тестування.
8) Навести скріншоти роботи програми. для заданої задачі
9) Дати відповіді на контрольні питання
Варіанти завдань
В Києві є декілька цікавих місць, а саме:
1. Червоний університет
2. Андріївська церква
3. Михайлівський собор
4. Золоті ворота
5. Лядські ворота
6. Фунікулер
7. Київська політехніка
8. Фонтан на Хрещатику
9. Софія київська
10. Національна філармонія
11. Музей однієї вулиці
Необхідно створити графічне зображення сполучень між ними,
враховуючи наступні
Постановка задачі
Не всі студенти НТУУ «КПІ ім. Ігоря Сікорського» полюбляють гуляти
пішки, тому компанія хлопців і дівчат з університету вирішила прокласти
транспортні маршрути від свого навчального закладу до інших
вищеперерахованих місць за умови найменшої вартості такого проекту.
Допоможіть їм прокласти такі маршрути.
Вхідні дані
1. Список місць, які студент хоче відвідати.
2. Інформація про доступні види транспорту та їхню вартість на
маршрутах між гуртожитком та кожним з місць.
Вихідні елементи
Список найдешевших маршрутів від гуртожитку до вище перерахованих
місць.
Інтерфейс користувача
Було прийнято рішення додати простий графічний інтерфейс користувача:
Користувач має змогу обрати алгоритм, за допомогою якого буде
здійснюватися пошук найдешевших маршрутів, та кінцеву точку із
випадаючого списку. Натиснувши кнопку “Виконати”, на екран
виводяться ціна маршруту та контрольні точки, якими проходить цей
маршрут. Завдяки цьому користувач не здатний нашкодити програмі,
ввівши неправильну інформацію. Адже всі можливі варіанти, які може
обрати користувач, виведені на головному інтерфейсі. Тому навіть
недосвідчені юзери не заплутаються у програмі.
Математична модель
Основні величини:
graph Graph Oб’єкт графа
graph.nodes List[Node] Масив точок графу
graph.adj_list List[Vertex] Список суміжності
graph.edges List[Edge] Масив ребер графу
vertex Vertex Вершина графу
vertex.node Node До якої точки
належить граф
vertex.edges List[Edge] Масив ребер вершини
edge Edge Oб’єкт ребра
edge.start Node Початкова точка ребра
edge.end Node Кінцева точка ребра
edge.weight float Вага ребра
node Node Об’ект точки графу
node.data string Опис точки
node.index int індекс точки у графі
Розробка алгоритму (Блок-схема)
import time
T = TypeVar('T')
def timeit(func):
@wraps(func)
start_time = time.perf_counter()
end_time = time.perf_counter()
return result
return timeit_wrapper
class Node:
__slots__ = [
"data",
"index"
]
data: str
index: Optional[int]
self.data = data
self.index = None
return f"{self.data}"
return f"{self.data}"
class Edge:
__slots__ = [
"start",
"end",
"weight"
start: Node
end: Node
weight: float
self.start = start
self.end = end
self.weight = weight
class Vertex:
__slots__ = [
"node",
"edges"
]
node: Node
edges: List[Edge]
self.node = node
if edges is None:
self.edges = []
else:
self.edges = edges
self.edges.append(edge)
class NodeDecorator:
__slots__ = [
"node",
"prov_dist",
"hops"
node: Node
prov_dist: float
hops: List[Node]
self.node = node
self.prov_dist = float("inf")
self.hops = []
self.hops.append(hop)
class MinHeap(Generic[T]):
__slots__ = [
"heap"
heap: List[T]
def __init__(self):
self.heap = []
@staticmethod
return (index - 1) // 2
@staticmethod
return 2 * index + 1
@staticmethod
return 2 * index + 2
return self.heap[self.get_parent_index(index)]
return self.heap[self.get_left_child_index(index)]
return self.heap[self.get_right_child_index(index)]
self.heap.append(value)
self.heapify_up()
index = len(self.heap) - 1
self.swap(self.get_parent_index(index), index)
index = self.get_parent_index(index)
if len(self.heap) == 0:
min_value = self.heap.pop()
self.heapify_down()
return min_value
def heapify_down(self) -> None:
index = 0
while self.has_left_child(index):
smaller_child_index = self.get_left_child_index(index)
smaller_child_index = self.get_right_child_index(index)
break
self.swap(index, smaller_child_index)
index = smaller_child_index
return len(self.heap) == 0
class Graph:
__slots__ = [
"nodes",
"adj_list",
"edges"
nodes: List[Node]
adk_list: List[Vertex]
edges: List[Edge]
self.nodes = nodes
self.edges = []
for i in range(len(self.nodes)):
self.nodes[i].index = i
self.nodes.append(node)
self.adj_list.append(Vertex(node=node))
self.adj_list[node1_ind].append(edge)
self.edges.append(edge)
@staticmethod
if isinstance(node, int):
return node
return node.index
return self.nodes[index]
node_ind = self.get_index_from_node(node)
return self.adj_list[node_ind].edges
@timeit
src = self.get_index_from_node(src)
dnodes = [NodeDecorator(node=node) for node in self.nodes]
dnodes[src].prov_dist = 0
dnodes[src].append_hop(dnodes[src].node)
visited = []
pq = MinHeap[NodeDecorator]()
pq.insert(dnodes[src])
min_decorated_node = pq.delete_min()
min_dist = min_decorated_node.prov_dist
hops = min_decorated_node.hops
visited.append(min_decorated_node.node)
connections = self.get_connections(min_decorated_node.node)
if tot_dist <
dnodes[self.get_index_from_node(edge.end)].prov_dist:
hops_cpy = list(hops)
hops_cpy.append(edge.end)
dnode = dnodes[self.get_index_from_node(edge.end)]
dnode.prov_dist = tot_dist
dnode.hops = hops_cpy
pq.insert(dnode)
return dnodes
@timeit
src = self.get_index_from_node(src)
dnodes[src].prov_dist = 0
dnodes[src].append_hop(dnodes[src].node)
dnodes[node2_ind].prov_dist = dnodes[node1_ind].prov_dist +
edge.weight
return dnodes
class Ui_MainWindow(object):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1080, 720)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
font = QtGui.QFont()
font.setPointSize(16)
self.label_2.setFont(font)
self.label_2.setAutoFillBackground(False)
self.label_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading |
QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop)
self.label_2.setIndent(0)
self.label_2.setObjectName("label_2")
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setObjectName("groupBox")
self.label_6 = QtWidgets.QLabel(parent=self.groupBox)
self.label_6.setGeometry(QtCore.QRect(20, 210, 481, 21))
font = QtGui.QFont()
font.setPointSize(11)
self.label_6.setFont(font)
self.label_6.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label_6.setObjectName("label_6")
self.label_3 = QtWidgets.QLabel(parent=self.groupBox)
font = QtGui.QFont()
font.setPointSize(10)
self.label_3.setFont(font)
self.label_3.setText("")
self.label_3.setTextFormat(QtCore.Qt.TextFormat.PlainText)
self.label_3.setScaledContents(True)
self.label_3.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|
QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
self.label_3.setWordWrap(True)
self.label_3.setObjectName("label_3")
self.layoutWidget = QtWidgets.QWidget(parent=self.groupBox)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.label_5 = QtWidgets.QLabel(parent=self.layoutWidget)
self.label_5.setObjectName("label_5")
self.verticalLayout.addWidget(self.label_5)
self.radioButton = QtWidgets.QRadioButton(parent=self.layoutWidget)
self.radioButton.setChecked(True)
self.radioButton.setObjectName("radioButton")
self.verticalLayout.addWidget(self.radioButton)
self.radioButton_2 = QtWidgets.QRadioButton(parent=self.layoutWidget)
self.radioButton_2.setObjectName("radioButton_2")
self.verticalLayout.addWidget(self.radioButton_2)
self.label_4 = QtWidgets.QLabel(parent=self.layoutWidget)
self.label_4.setObjectName("label_4")
self.verticalLayout.addWidget(self.label_4)
self.comboBox = QtWidgets.QComboBox(parent=self.layoutWidget)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.verticalLayout.addWidget(self.comboBox)
self.pushButton = QtWidgets.QPushButton(parent=self.layoutWidget)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.label = QtWidgets.QLabel(parent=self.centralwidget)
self.label.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft)
self.label.setText("")
self.label.setPixmap(QtGui.QPixmap("graph.png"))
self.label.setScaledContents(True)
self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label.setObjectName("label")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
"6. Фунікулер\n"
""))
self.pushButton.setText(_translate("MainWindow", "Виконати"))
self.graph = None
self.setupUi(self)
self.setWindowTitle("Теорія Алгоритмів")
self.setWindowIcon(QIcon('neural.png'))
self.create_graph()
self.setFixedSize(1080, 720)
self.label_2.setStyleSheet("margin-left: 15px;")
self.pushButton.clicked.connect(self.click)
self.dijkstra_list = None
self.bellman_ford_list = None
def create_graph(self):
a = Node(data="Червоний університет")
b = Node(data="Андріївська церква")
c = Node(data="Михайлівський собор")
d = Node(data="Золоті ворота")
e = Node(data="Лядські ворота")
f = Node(data="Фунікулер")
g = Node(data="Київська політехніка")
h = Node(data="Фонтан на Хрещатику")
i = Node(data="Софія київська")
j = Node(data="Національна філармонія")
self.start = g
self.graph.connect(g, a, 8)
self.graph.connect(g, d, 8)
self.graph.connect(a, d, 8)
self.graph.connect(g, h, 8)
self.graph.connect(a, h, 8)
self.graph.connect(h, e, 8)
self.graph.connect(h, j, 8)
self.graph.connect(j, e, 8)
self.graph.connect(h, f, 8)
self.graph.connect(h, k, 8)
self.graph.connect(d, i, 14)
self.graph.connect(i, c, 6)
self.graph.connect(i, b, 8)
self.graph.connect(b, c, 6)
def click(self):
index = self.comboBox.currentIndex()
end = self.graph.get_node_from_index(index)
if self.radioButton.isChecked():
self.dijkstra_list = self.graph.dijkstra(self.start)
distances = self.dijkstra_list
else:
self.bellman_ford_list = self.graph.bellman_ford(self.start)
distances = self.bellman_ford_list
distance = distances[index]
route = ""
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Перевірка правильності
Перевірка правильності роботи алгоритму
Результат Призначення тексту
Вхідні дані
radioButton comboBox
1 Михайлівській Відомий Загальна перевірка
собор працездатності алгоритму та
коректності результату
2 Музей однієї Відомий Загальна перевірка
вулиці працездатності алгоритму та
коректності результату
Вхідні дані
MainWindow Відомий Перевірка відображення графічного інтерфейсу
Переваги:
● Дозволяє розбити складну задачу на менші частини, що
оптимальним
Недоліки:
рішення;
розробки
Переваги:
Недоліки:
● Є вразливим до попадання в локальні мінімуми, що
Переваги:
Недоліки:
кожному етапі
Висновок
Виконуючи практикум № 2 з дисципліни - Теорія алгоритмів на
тему “Методи розробки алгоритмів. Частина 1”, ми використовували
Python для програмування. Оскільки ця мова програмування
зарекомендувала себе, як простий та багатофункціональний
інструмент, який ще й можна легко модифікувати.
Аби виконати практикум ми мали обрати певні алгоритми. Наш
вибір впав на алгоритми Беллмана-Форда та Дейкстри. Саме їхні
принципи ми відтворювали за допомогою пайтону для вирішення
нашого завдання. Як результат - ми змогли достовірно отримати всі
можливі шляхи та їх ціну, аби “спланувати” прогулянку.
Дякую за увагу.
Слава Україні!