Описание алгоритма решения задачи

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ

Государственное образовательное учреждение высшего профессионального образования

«Тюменский Государственный Нефтегазовый университет»

ИНСТИТУТ ГЕОЛОГИИ И НЕФТЕГАЗОДОБЫЧИ

КАФЕДРА ИНФОРМАТИКИ И ВЫЧИСЛИТЕЛЬНОЙ ТЕХНИКИ

КУРСОВАЯ РАБОТА

по дисциплине «Дискретная Математика»

Тема: Разработка алгоритма и программного обеспечения для решения прикладной задачи теории графов

Выполнил:

студент группы АСОиУз - 09 -1

Юга М.Н.

Проверила:

старший преподаватель каф. ИВТ, Гапанович И.В.

Тюмень 2012

Оглавление

1) Постановка задачи

2) Описание алгоритма решения задачи

3) Ручной просчет

4) Листинг программы

5) Литература


Постановка задачи

Построить гамильтонову цепь в графе, используя рекурсивный алгоритм генерации всех перестановок вершин в антилексикографическом порядке.


Описание алгоритма решения задачи

Пусть G псевдограф. Цепь (цикл) в G называется гамильтоновой (гамильтоновым), если она (он) проходит через каждую вершину псевдографа G ровно один раз. Простейшим достаточным условием существования гамильтоновых цепей и циклов в графе является его полнота. Граф G называется полным, если каждая его вершина смежна со всеми остальными вершинами. Необходимым условием существования гамильтоновых цепей и циклов в графе G является связность данного графа.

Приведем некоторые наиболее простые методы выделения гамильтоновых цепей и циклов в графе G =(V,X), где V = { v1,v2,…,vn }. Самым простым является метод перебора всевозможных перестановок vi1,vi2,…,vin множества V. Для каждой из них проверяем, является ли vi1vi2…vin маршрутом в G. Если является, то vi1vi2 …vin - гамильтонова цепь в G, в противном случае переходим к другой перестановке. Тогда по окончании перебора будут выделены все гамильтоновы цепи в графе G. Аналогично для выделения гамильтоновых циклов перебираем всевозможные перестановки v1vi1vi2 …vin-1 множества V, для каждой из которых проверяем, является ли v1vi1vi2…vin-1v1 маршрутом в G. Если является, то v1vi1vi2…vin-1v1 – гамильтонов цикл в G, в противном случае переходим к следующей перестановке. Тогда по окончании перебора будут выделены все гамильтоновы циклы в графе G. Очевидно, что при выделении гамильтоновых цепей придется перебрать n! перестановок, а при выделении всех гамильтоновых циклов - (n -1)! перестановок. При этом в случае полного графа ни одна из перестановок не окажется отброшенной, т.е. данный метод является эффективным для графов, близких к полным.

Антилексикографический порядок (обозначим <¢) определяется следующим образом: <x1,x2,…xn> <¢ <y1,y2,…,y n> Û существует такое k £ n, что xk > yk и xp = yp для каждого p > k.

Для примера приведем перестановки множества X = {1,2,3} в антилексикографическом порядке: 123, 213, 132, 312, 231, 321.

Алгоритм генерирования перестановок в антилексикографическом порядке можно сформулировать при помощи рекурсивной процедуры, на вход которой подается m – количество первых элементов массива P = { 1, 2, 3…m }, для которого генерируются перестановки.

Процедура swap() меняет местами элементы в массиве P, а процедура reve () представляет элементы отрезка массива [0..m] в обратном порядке.


Ручной просчет

Пусть имеем граф G = (V, X) заданный матрицей смежности:

  v1 v2 v3
v1      
v2      
v3      


Построим все перестановки множества вершин V = { v1, v2, v3}.

Просматриваем перестановки множества V на предмет наличия гамильтоновой цепи:

{ v1, v2, v3} – нет ребра { v2, v3}

{ v2, v1, v3} – гамильтонова цепь.

{ v1, v3, v2} – нет ребра { v3, v2}

{ v3, v1, v2} – гамильтонова цепь.

{ v2, v3, v1} – нет ребра { v2, v3}

{ v3, v2, v1} – нет ребра { v3, v2}

Значит гамильтоновых цепей две:

2 1 3 и 3 1 2
Листинг программы

#include <stdio.h>

#define MAX 1010

int n;

int g[MAX][MAX];

bool used[MAX];

int p[MAX];

bool One;

inline void swap(int &a,int &b) {int t = a;a = b;b = t;}

inline void reve(int x) {int j = 0; while(j < x) {swap(p[j],p[x]);x--;j++;}}

inline bool check(){for(int i = 0;i < n-1;i++) if(!g[p[i]][p[i+1]]) return false; return true;}

void next_perm(int m)

{

if(m == 0)

{

if(check())

{

for(int i = 0;i < n;i++) printf("%d ",p[i]);

printf("\n");

One = true;

}

}else{

for(int i = 0;i <= m;i++)

{

next_perm(m-1);

if(i < m)

{

swap(p[i],p[m]);

reve(m-1);

}

}

}

}

int main()

{

freopen("input.txt","r",stdin);

freopen("output.txt","w",stdout);

scanf("%d",&n);

for(int i = 1;i <= n;i++)

for(int j = 1;j <= n;j++)

scanf("%d",&g[i][j]);

for(int i = 0;i < n;i++) p[i] = i+1;

next_perm(n-1);

if(!One)

printf("No paths");

return 0;

}


Литература

1. Т. Кормен, Ч. Лейзерсон, Р. Ривест, К. Штайн Алгоритмы: построение и анализ (второе издание), Вильямс, 2007 г.

2. Д. Кнут Искусство программирования, Вильямс, 2006 г.

3. Ф.А. Новиков Дискретная математика для программистов, Питер, 2000 г.

4. Б.Н. Иванов Дискретная математика. Алгоритмы и программы, Лаборатория базовых знаний, 2003 г.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: