Есть интересная наука, которая называется Теория графов. В программировании можно встречать много задач, которые на теорию графов опираются. Я не буду переписывать о графах из других источников, а опишу немного по-своему. Здесь будет описан именно Гамильтонов цикл. Это первое мое знакомство с материалами из теории графов, поэтому здесь простой и не глубокий материал.
Чтобы объяснить, что такое Гамильтонов цикл, я приведу 2 визуальных примера. Очень простой и чуть-чуть посложнее.
Советую перерисовать дом с номерами на лист бумаги, удобнее будет смотреть позже.
Это самый простой пример. Слева нарисован рисунок. Справа у рисунка обозначены некоторые точки. Если представить, что линии — это дороги, а точки — пункты назначения, то существует множество маршрутов между этими точками. Предлагаю сыграть в простую игру.
Надеюсь смысл понятен. Вы должны вернутся на базу один и целым. База — это точка выхода. Откуда вышли, над туда прийти.
Вот пример. Поможет понять правило игры.
Старт точка 4:
4—>3—>1—>2—>4 Снайпер с точки 4 вас убил за то, что у вас снайпер остался. Ведь вы вернулись на базу не выполнив приказ.
Если делать проход по 3-4, то дальше в одной из точек будете убиты.
Но можно пройти 4—>5—>3—>1—>2—>4, снайперы на месте, вы на базе. Совсем не обязательно по всем дорогам шататься, главное посещение нужных точек и не попадаться на глаза оставленным снайперам.
Если бы между 2 и 4 был пункт 6, то можно было двигаться 2—>4—6, дальше снайпер. Если бы в 6 стоял снайпер, а вы шли 2—>4, то снайпер 6 вас не трогает, вы не остановились и прошли прямо.
Надеюсь освоились с правилом и поняли, что от вас требуется.
Такой маршрут можно рассчитать с помощью теории графов и запрограммировать это в программу..
Ниже исходного кода есть еще один рисунок. Поиграйте с ним немного, пытаясь найти нужный маршрут, согласно нашему правилу. Может помочь в развитии уметь думать и вместе с этим лучше поймете, что такое Гамильтонов цикл вообще.
А сейчас поясню как оно программируется. Для начала я буду использовать матрицу смежности.
Чтобы было понятнее, попытаюсь объяснить. Давайте смотреть на нумерованный рисунок и отталкиваться от нумерованных узлов по порядку. (удобнее если вы все-таки срисовали)
1) 1 соединен с 2 и 3 (значит 1 смежно с 2 и 3)
2) 2 соединен с 4 и 1
3) 3 соединен с 1, 4 и 5
4) 4 соединен с 2, 3 и 5
5) 5 соединен с 3 и 4
Из этой информации нужно создавать матрицу. Сначала просто пронумеруем поле для матрицы
1 2 3 4 5
1
2
3
4
5
Отсчет у нас от единицы. Можно делать от нуля, но мне оказалось проще так. Теперь постепенно заполняем матрицу нулями и единицами. Смотрим на информацию выше (там где про соединения) и расставляем по матрице значения.
1) 1 соединен с 2 и 3 (значит 1 смежно с 2 и 3)
———————
1 2 3 4 5
1 0 1 1 0 0
2
3
4
5
———————
Видите связь? Внимательно присмотритесь. Слева у нас номер узла, сверху номер другого узла. Если узлы соединены, то ставим 1, если нет, то 0. Дальше заполняем матрицу аналогично. Итоговая матрица по рисунку получается
———————
1 2 3 4 5
1 0 1 1 0 0
2 1 0 0 1 0
3 1 0 0 1 1
4 0 1 1 0 1
5 0 0 1 1 0
———————
Я очень надеюсь, что смог объяснить как составляется матрица смежности, потому что эту матрицу смежности мы будем подставлять в программу.
Исходник Гамильтонова цикла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <iostream.h> #include <stdlib.h> const int n=5; int c[n] ; // номер хода, на котором посещается вершина int path[n]; // номера посещаемых вершин int v0=2; // начальная вершина //Матрица смежности int a[n][n]= { 0,1,1,0,0, 1,0,0,1,0, 1,0,0,1,0, 0,1,1,0,1, 0,0,1,1,0 }; void prnt(void) { int p; for ( p = 0 ; p<n ; p++) cout<<path[p]+1<<"\t"; cout<<path[0]+1 ; cout<<"\n" ; } //подпрограмма нахождения гамильтонова цикла int gamilton ( int k) { int v,q1=0; for(v=0; v<n && !q1; v++) { if(a[v][path[k-1]]||a[path[k-1]][v]) { if (k==n && v==v0 ) q1=1; else if (c[v]==-1) { c[v] = k ; path[k]=v; q1=gamilton (k+1) ; if (!q1) c[v]=-1; } else continue; } } return q1; } int main() { int j; system("CLS"); cout<<"Гамильтонов цикл:\n"; for(j=0;j<n;j++) c[j]=-1; path[0]=v0 ; c[v0]=v0; if(gamilton (1)) prnt(); else cout<<"Нет решений\n"; cin.get(); return 0; } |
Программа есть. Смотрим результат.
3—>1—>4—>2—>5—>3
Программа показала нам нужный маршрут нашей простецкой игры.
Давайте немного усложним сам рисунок для теста программы. Как я предлагал выше, попробуйте сами найти нужный маршрут, согласно нашим правилам. Думаю это может вызывать некоторые затруднения. Найти без помощи компа.
Даже если пробовали, но не особо получается, то ведь мы теперь знаем о существовании Гамильтонова цикла и получили о Гамильтоновом цикле первое представление. Даже знаем, что этот Гамильтоновый цикл можно заложить в исходник программы и знаем как. Единственное неудобство — это составление и подставление матрицы смежности в программу. Здесь 13*13 элементов в матрице, поэтому требуется быть очень внимательным.
Я не буду повторять исходник. Там достаточно поменять N=13 и поменять матрицу на новую. Имеет смысл понять как составляется матрица. Выше я описал насколько смог, чтоб было проще разбираться, здесь показываю итоговую для текущего рисунка
0,1,0,0,0,1,0,0,0,0,0,0,0,
1,0,0,1,0,0,0,1,0,0,0,0,0,
0,0,0,1,1,0,1,0,1,0,0,0,0,
0,1,1,0,1,0,0,1,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,1,0,0,0,
1,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,0,0,1,0,1,1,0,0,0,0,
0,1,0,1,0,1,1,0,0,0,0,0,0,
0,0,1,0,0,0,1,0,0,1,1,0,0,
0,0,0,0,1,0,0,0,1,0,1,1,0,
0,0,0,0,0,0,0,0,1,1,0,0,1,
0,0,0,0,1,0,0,0,0,1,0,0,1,
0,0,0,0,0,0,0,0,0,0,1,1,0
Вы можете сами пробовать свои силы в составлении матрицы. Сверить очень просто — подставить мою в программу и посмотреть результат, потом вашу и посмотреть результат. А если вы поняли правило предложенной игры, то даже сверять результаты двух запусков программы не надо, достаточно визуального прохода по точкам. Можно на листе бумаги закрашивать точки со снайпером.
P.S. Такое вот обобщенное представление Гамильтонова цикла из теории графов в C++ получилось создать.
Большое Спасибо!!!!
Опиши Гамильтонов Путь
Хороший алгоритм)) У меня немного другой и я с помощью него сделал вот такую прогу http://yadi.sk/d/D7AIMv7P2_zYO это мой курсач))
Данила , спасибо большое за программу в свободном доступе , изящно , красиво и полезно.Добра тебе 🙂
Спасибо автору за полезную статью.
Друг, перезалей файл.
какой файл?
Автор! Вы спасаете тонны студентов ежегодно! Спасибо большое за открытые исходники) две группы излучают добро на вашу душу)
Спасибо за программу!
Можете пояснить для чего нужны переменные q1 и k? и что они выполняют
в 42 строке c[v]=-1
откуда у нас появилось значение -1?
a vi mojete obiasnic sto int gamilton(int k) delaet? algoritm v detaliax
Программа есть. Смотрим результат.
3—>1—>4—>2—>5—>3
Почему? С первой вершины нет пути к четвертой?
Исправили бы ошибки и только потом выложили бы
а если у меня другой граф? как мне програму использовать?
матрица вводитса в начале и все, не используется
Вопрос не очень понятен.
Если Гамильтонов цикл и дугой граф, то делается другая матрица. Правило составления описано в статье.
Программу писал полный мудила, стиль говно, глобальные переменные, никаких комментов… ЕЩе и не объяснил алгоритм поиска цикла
можешь скинуть программу?
Что за хуйня про снайперов…
Снайперы — это полный кринж конечно. Я поржала)))