Министерство образования и науки Российской федерации
Комсомольский-на-Амуре государственный технический университет
Кафедра МОП ЭВМ
Лабораторная работа №2
по дисциплине: САОД (Часть 2)
Задание:
Решить задачу коммивояжера методом перебора с возвратом. Цены билетов заданы с помощью симметричной n´n матрицы.
Ход работы:
Задан граф (рисунок 1) представляющий схему пути перемещения. Для решения задачи коммивояжера необходимо обойти все города и вернутся в исходный за минимальную цену, т.е. эта задача сводится к поиску гамильтоново цикла в графе, с минимальными значениями путей между узлами.
В этой задаче надо перебрать все гамильтоновы циклы и найти среди них наименьший.
Задача перебора гамильтоновых циклов. Путь будем представлять в виде последовательности вершин (x1,x2,…,xk). Такой путь будет простым если и только если xi = xj для всех i¹j, i,jÎ{1,2,…,k}.
Определим предикаты.
Pk(x1,x2,…xk)=1 Û xi¹xj, при 1 £ i < j £ k, и {xi,xi+1} – ребра при 1 £ i < k;
Q(x1,x2,…xk)=1 Û k=n и {xn,x1} – ребро.
Для того, чтобы последовательности вершин (x1,x2,…xk) удовлетворяли условию xi¹xj, будем раскрашивать вершины этих последовательностей и учитывать раскраску при выборе очередей вершины. Гамильтонов цикл, с началом x1=n0, представим как последовательность (x1,x2,…,xn,xn+1), где xn+1=x1=n0.
Пусть Ak – множество вершин, смежных с xk, cn - раскраска вершины n. Согласно общей схеме имеем следующий приближенный текст для перебора гамильтоновых циклов;
Листинг программы:
#include <iostream.h> //библиотека ввода-вывода
#include <conio.h> //консольный ввод-вывод
void gamilton(int); //подпрограмма гамильтонова цикла
void print(); //подпрограмма подсчёта суммы
int graph[6][6] = //граф
{
{ 0, 5, 15, 5, 10, 25},
{ 5, 0, 5, 0, 5, 10},
{15, 5, 0, 0, 0, 5},
{ 5, 0, 0, 0, 5, 15},
{10, 5, 0, 5, 0, 5},
{25, 10, 5, 15, 5, 0}
};
int u, v, u0, v0; //начальные и текущии координаты перебора графа
int sum, minsum = 32000; //текущая и мин. сумма
int minput[6]; //мин. путь
int put[6]; //текущий путь
int main() //главная подпрограмма
{
u0 = v0 = 0; //устанавливаем координаты в начало
u = u0;
v = v0;
graph[v0][u0] = 1;
gamilton(0); //запускаем перебор графа
print();
cout << "Min put: " << endl; //вывод "Min put: "
for (int i = 0; i < 6; i++)
cout << " " << minput[i] << " ";//вывод мин. пути
cout << endl << "cost: " << minsum << endl;//вывод суммы
getch(); //задержка экрана
}
void gamilton(int hod) //подпрограмма гамильтонова цикла
{
int i;
for (i = 0; i <= 5; i++)
{
if (i != v && graph[i][v])
{
if (i == v0 && hod == 5)
{
print();
}
if (!(graph[i][i]))
{
v = i;
put[hod] = i; //текший город записываем в путь
graph[i][i] = 1;
gamilton(hod + 1); //рекурсивный вызов
graph[i][i] = 0;
v = i;
}
}
}
}
void print() //подпрограмма подсчёта суммы
{
sum = 0; //текущая сумма =0
int i;
for (i = 0; i < 5; i++)
{
sum += graph[put[i]][put[i + 1]]; //сумируем цену пути
}
sum += graph[put[i]][put[0]];
if (sum < minsum) //если тек. сумма < минимальной:
{
minsum = sum;
for (int i = 0; i < 6; i++)
minput[i] = put[i];
}
}
Результат выполнения программы:
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.