Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы по ПиАА 2024 / Baraeva_Elizaveta_lb3

.doc
Скачиваний:
0
Добавлен:
09.09.2026
Размер:
75 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В. И. Ульянова (Ленина)

Кафедра МО ЭВМ

отчет

по лабораторной работе 3

по дисциплине «Построение и анализ алгоритмов»

Тема: Задача коммивояжёра

Студентка гр. 2383

Бараева Е. Н.

Преподаватель

Шевелева А. М.

Санкт-Петербург

2024

Цель работы.

Решить задачу коммивояжёра при помощи метода ветвей и границ, а также провести исследование точности работы ветвей и границ по сравнению с жадным алгоритмом на полном графе.

Задание.

Дано: дан полный граф G=(V, E), где V (|V| <= 20) – это вершины графа; E – ребра графа. W(G) – весовая, ассиметричная матрица графа, где wij > 0, wij – натуральные числа, i ≠ j и wij=inf, если i=j.

Требуется:

Найти минимальный гамильтонов цикл и вывести матрицу пути и вес получившегося пути.

Решить задачу методом ветвей и границ.

В отчете должна быть таблица с тестированием вашего кода. Обязательна возможность считывания матрицы из файла: первая строчка размер матрицы, последующие – сама матрица. Бесконечные ребра отмечайте «-1».

Пример:

Ввод:

3

-1 1 3

3 -1 1

1 2 -1

Вывод:

[0, 1, 2], вес – 3.

Исследование: вещественные положительные числа в интервале [0,1], анализ точности работы ветвей и границ по сравнению с жадным алгоритмом на полном графе.

Выполнение работы.

  • get_bnb_path() – функция, в которой создается очередь queue и пустой список best_path, в котором будет храниться лучший найденный путь. vertexes_amount – количество вершин в графе, min_cost инициализируется как бесконечность. В очередь добавляется кортеж (текущая стоимость, путь), начиная с вершины 0. Пока очередь не пуста, извлекается кортеж с наименьшей стоимостью. Если текущий путь образует гамильтонов цикл и имеет минимальную стоимость, то обновляются min_cost и best_path. Для каждой вершины, кроме последней в текущем пути, рассматриваются возможные следующие вершины и добавляются в очередь с учетом стоимости перехода. В конце функции возвращаются минимальная стоимость и лучший путь.

  • read_data() – функция, которая запрашивает у пользователя способ ввода данных (из файла или с консоли). Если выбран ввод из файла, то запрашивается его имя, затем считываются количество вершин n и матрица смежности из файла. Если выбран ввод с консоли, то от пользователя запрашиваются такие же параметры. В конце функция возвращает количество вершин n.

  • В блоке if name == "main" создается пустая матрица matrix, затем вызываются функции read_data для чтения данных и get_bnb_path для нахождения минимального гамильтонова цикла. В конце выводится найденный цикл и его вес.

Тестирование.

Результаты тестирования представлены в табл. 1.

Таблица 1 – Результаты тестирования

№ п/п

Входные данные

Выходные данные

Комментарии

1.

3

-1 1 3

3 -1 1

1 2 -1

[0, 1, 2], вес - 3.0

Граф с 3-я вершинами. Верно.

2.

4

-1 0.774 0.926 0.15

0.192 -1 0.054 0.137

0.658 0.469 -1 0.388

0.708 0.738 0.206 -1

[0, 3, 2, 1], вес - 1.017

Граф с 4-я вершинами. Верно.

3.

5

-1 0.465 0.878 0.011 0.22

0.285 -1 0.36 0.469 0.403

0.536 0.839 -1 0.813 0.17

0.679 0.767 0.785 -1 0.623

0.476 0.754 0.77 0.626 -1

[0, 3, 1, 2, 4], вес - 1.784

Граф с 5-ю вершинами. Верно.

4.

6

-1 0.283 0.729 0.256 0.585 0.533

0.103 -1 0.3 0.751 0.037 0.933

0.35 0.841 -1 0.676 0.467 0.701

0.418 0.941 0.252 -1 0.42 0.509

0.854 0.431 0.16 0.504 -1 0.341

0.319 0.588 0.188 0.219 0.278 -1

[0, 1, 4, 5, 3, 2], вес - 1.482

Граф с 6-ю вершинами. Верно.

Исследование.

Для проведения исследования был создан генератор матриц смежности полных графов с вершинами от 3 до 11, была написана функция жадного алгоритма. По графику (см. рис. 1) можно сделать вывод о том, что при количестве вершин равном 3 и 4 алгоритмы будут работать одинаково. Однако, если вершин больше 4, то точность жадного алгоритма начинает меняться. Это обусловлено тем, что жадный алгоритм принимает оптимальное решение отталкиваясь от той вершины, где он находится, а метод ветвей и границ обходит все варианты и выбирает лучший. Погрешность жадного алгоритма не столь большая, потому что ячейки матрицы смежности принимают значения от 0 до 1. Если множество значений не было бы ограниченно, то точность алгоритма заметно снизилась.

Рисунок 1 – График исследования точности алгоритмов

Вывод.

Была решена задача коммивояжёра при помощи метода ветвей и границ.

Для этого в ходе выполнения лабораторной работы была написана программа для поиска минимального гамильтонова цикла, считывающая данные с консоли или из файла, зависящая от выбора пользователя. Также был создан генератор тестов для тестирования написанной программы.

В ходе исследования выяснилось, что при количестве вершин меньшем 5 оба алгоритма работают одинаково. Но, если вершин больше 4, то точность жадного алгоритма начинает уступать методу ветвей и границ. Это связано с тем, что жадный алгоритм принимает оптимальное решение отталкиваясь от той вершины, где он находится, а метод ветвей и границ обходит все варианты и выбирает лучший. Именно поэтому метод ветвей и границ работает точнее, но дольше жадного алгоритма.

ПРИЛОЖЕНИЕ А ИСХОДНЫЙ КОД ПРОГРАММЫ

Название файла: branch_and_bound.py

import heapq

INF = float('inf')

def get_bnb_path():

queue, best_path = [], []

vertexes_amount, min_cost = n, INF

heapq.heappush(queue, (0, [0]))

while queue:

current_cost, path = heapq.heappop(queue)

if path[-1] == path[0] and len(path) == vertexes_amount + 1:

if current_cost < min_cost:

min_cost = current_cost

best_path = path

continue

last_vertex = path[-1]

for next_vertex in range(vertexes_amount):

if next_vertex not in path or (next_vertex == path[0] and len(path) == vertexes_amount):

heapq.heappush(queue, (current_cost + matrix[last_vertex][next_vertex], path + [next_vertex]))

return min_cost, best_path[:-1]

def read_data(graph):

print("Enter 0 to enter from file or 1 to enter from console:")

input_type = input()

if input_type == '0':

print("Enter file name:")

file_name = input()

with open(file_name, 'r') as file:

n = int(file.readline())

for i in range(n):

graph.append([float(j) for j in file.readline().split()])

elif input_type == '1':

print("Enter data:")

n = int(input())

for i in range(n):

graph.append([float(j) for j in input().split()])

else:

print("Incorrect input type!")

exit(0)

return n

if __name__ == "__main__":

matrix = []

n = read_data(matrix)

final_cost, final_cycle = get_bnb_path()

print(f'{final_cycle}, вес - {round(final_cost, 3)}')

Название файла: greedy_algorithm.py

from branch_and_bound import read_data

def get_path_using_greedy_algorithm():

min_path, min_cost = [], float('inf')

for start in range(n):

visited, path = [False] * n, [start]

cost, current = 0, start

visited[current] = True

for _ in range(n - 1):

next_node = min((i for i in range(n) if not visited[i]), key=lambda x: matrix[current][x])

visited[next_node] = True

cost += matrix[current][next_node]

path.append(next_node)

current = next_node

cost += matrix[current][start]

if cost < min_cost:

min_cost = cost

min_path = path

return min_cost, min_path

if __name__ == "__main__":

matrix = []

n = read_data(matrix)

final_cost, final_cycle = get_path_using_greedy_algorithm()

print(f'{final_cycle}, вес - {round(final_cost, 3)}')

7

Соседние файлы в папке Лабы по ПиАА 2024